Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InvalidCastException : Unable to cast object of type 'T' to type 'Moq.IMocked`1[T]' #33

Closed
Janus88 opened this issue Mar 20, 2020 · 5 comments · Fixed by #34
Closed
Assignees
Labels

Comments

@Janus88
Copy link

Janus88 commented Mar 20, 2020

When trying to set up a partial mocked test I get the following error:

InvalidCastException : Unable to cast object of type 'T' to type 'Moq.IMocked`1[T]'

In this issue it was marked as resolved:
#9

I'm using XUnit 2.4.1 and Autofac.Extras.Moq 5.0.0

What I've found out so far is. As long as I mock a class without dependencies it works. As soon as there is a constructor injection needed the error occurs. I've made two tests for verifying the issue. The first runs fine, the second one throws the error:

public class SUTWithoutDependency : ISUT
    {
        public int Testing()
        {
            return DoSomeThing() + DoSomeThingInternal();
        }
        public virtual int DoSomeThing() => 5;

        public virtual int DoSomeThingInternal() => 5;
    }

    public class TestClassWithoutDependency
    {
        // This test works fine!!!
        [Fact]
        public void RunTest()
        {
            using (var mock = AutoMock.GetLoose())
            {
                var sut = mock.Mock<SUTWithoutDependency>();
                sut.CallBase = true;
                sut.Setup(s => s.DoSomeThing()).Returns(37);
                var res = sut.Object.Testing();
                Assert.Equal(42, res);
            }
        }
    }
    public class SUTWithDependency : ISUT
    {
        private readonly IDependency _dependency;

        public SUTWithDependency(IDependency dependency)
        {
            _dependency = dependency;
        }
        public int Testing() => DoSomeThing() + DoSomeThingInternal() + _dependency.DoSomethingExternal();
        public virtual int DoSomeThing() => 5;

        public virtual int DoSomeThingInternal() => 5;
    }
    public class TestClassWithDependency
    {
        // This test throws exception:
        // Unable to cast object of type 'Tests.SUTWithDependency' 
        // to type 'Moq.IMocked`1[Cube.Lvs.Service.Tests.SUTWithDependency]'.
        [Fact]
        public void RunTest()
        {
            using (var mock = AutoMock.GetLoose())
            {
                
                mock.Mock<IDependency>().Setup(s => s.DoSomethingExternal()).Returns(7);
                var sut = mock.Mock<SUTWithDependency>();
                sut.CallBase = true;
                sut.Setup(s => s.DoSomeThing()).Returns(30);
                var res = sut.Object.Testing();
                Assert.Equal(42, res);
            }
        }
    }
    public interface ISUT
    {
        int DoSomeThing();
    }

    public class Dependency : IDependency
    {
        public int DoSomethingExternal()
        {
            return 5;
        }
    }

    public interface IDependency
    {
        int DoSomethingExternal();
    }
@alistairjevans alistairjevans self-assigned this Mar 22, 2020
@alistairjevans
Copy link
Member

Ok, so there's two things going on here.

First, there is a bug here, but only in the sense that we're not throwing the right exception if you attempt to mock something that we cannot mock. We'll fix that so the right exception gets thrown.

Secondly, the reason an exception is being thrown is that this integration doesn't let you create a mock that does not have a public constructor with zero parameters. This is partly due to a restriction on how we create mocks, but also because it's a slight code smell to mock a class with constructor parameters. You normally try to mock interfaces, because they don't have a problem.

Additionally, in your original test, you don't actually have any object under test:

[Fact]
public void RunTest()
{
    using (var mock = AutoMock.GetLoose())
    {
        // Mock a dependency, check, that's all fine.   
        mock.Mock<IDependency>().Setup(s => s.DoSomethingExternal()).Returns(7);
        
        // Mock another class...
        // ...oh, but we're not actually testing the class itself, 
        // we're testing a mock!
        var sut = mock.Mock<SUTWithDependency>();
        sut.CallBase = true;
        sut.Setup(s => s.DoSomeThing()).Returns(30);
        var res = sut.Object.Testing();

        // Assert something (but we're actually testing mock behaviour).
        Assert.Equal(42, res);
    }
}

Your object under test should be created, using the Create method, instead of mocking it:

[Fact]
public void RunTest()
{
    using (var mock = AutoMock.GetLoose())
    {
        // Mock a dependency, check, that's all fine.   
        mock.Mock<IDependency>().Setup(s => s.DoSomethingExternal()).Returns(7);
        
        // Now create the class that is actually under test.
        // This will correctly inject IDependency into the constructor.
        var underTest = mock.Create<SUTWithDependency>();
        
        var res = underTest.Testing();

        // Assert something. We're now actually testing the class.
        Assert.Equal(42, res);
    }
}

I hope that helps. I'm progressing a fix for throwing the right defect now.

@Janus88
Copy link
Author

Janus88 commented Mar 23, 2020

Ok, since 5.0.1 there is another exception. As alistairjevans wrote, I should instantiate with the SUTWithDependency class with the Create method.

But how do I achieve this???
sut.Setup(s => s.DoSomeThing()).Returns(30);

Best Regards
Helmut

@alistairjevans
Copy link
Member

My question would be, why are you mocking SUTWithDependency at all? What class is actually under test here?

@Janus88
Copy link
Author

Janus88 commented Mar 23, 2020

Oh its a business application with heavy business logic. SUT is a service containing business logic. It depends on other services (with biz logic) as well as EF Core repos. As well SUT is sometimes a composition of multiple methods. When I run a test I only want to test a single method and not all methods, services or repos it depends on.

@alistairjevans
Copy link
Member

Ok, well a general principle would be that any internal dependencies (e.g. private methods) should be part of the test. If they cannot be, then it suggests some of the contents of those methods should be factored out into another service, that can itself then be mocked and injected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants