Jay
Jay

Reputation: 10138

Assert that a call was not made with any generic parameters using FakeItEasy

Disclaimer - this is not the same question as How to use FakeItEasy to assert a method was not called

Explanation

I have a piece of code which registers stuff with an IOC container, and I can use FakeItEasy in my tests to ensure that registrations are made.

I am trying to work out how to ensure that unexpected calls are not made.

Quick repo (problem boiled down to a couple of test classes - this is not a real implementation)

public class Foo
{
    private readonly ICustomContainer m_CustomContainer;

    public Foo(ICustomContainer customContainer)
    {
        m_CustomContainer = customContainer;
    }

    public void Bar()
    {
        m_CustomContainer.Register<IMyInterface, IMyImplementation>();
    }
}

public interface ICustomContainer
{
    void Register<TInterface, TImplementation>() where TImplementation : TInterface;
}

public class UnitTest1
{
    [Fact]
    public void Test1()
    {
        //Arrange
        ICustomContainer fake = A.Fake<ICustomContainer>();
        Foo objectUnderTest = new Foo(fake);

        //Act
        objectUnderTest.Bar();

        //Assert
        A.CallTo(() => fake.Register<IMyInterface, IMyImplementation>()).MustHaveHappened();
        //A.CallTo(() => fake.Register<???>()).MustNotHaveHappened();  //Any generic parameter apart from <IMyInterface, IMyImplementation> must not have happened
    }
}

The above test will pass - which is correct. If in the future I was to add another registration in the Bar(), it would still pass - which isn't so good as my test is only testing known scenarios.

What I am trying to achieve

So, given the interface defined above for ICustomContainer which is my IOC container, I would like to ensure that it is called only as expected.

What I have already investigated

Having used other mocking frameworks in the past such as TypeMock Isolator, I could set the fake object up to throw exceptions unless specific (expected) calls are made. I don't know if I can do this with FakeItEasy. Also TypeMock Isolator doesn't support .NET Core, so it is no good to me.

If I had a method that didn't use a generic parameter, I could get FakeItEasy to count the number of times that the method had been invoked, and expect that it had been invoked with any arguments in addition to testing the expected calls. That is certainly an option, but means that I have to create a facade over my interface (as an extension method or a wrapper, I guess) to take in type parameters rather than generic parameters, which means that I lose the pre-compile time warnings I get with the generic parameter constraint.

The actual question

How do I amend my test so that I can assert that an unexpected call was not made with any generic parameters other than those I was expecting using .NET Core / FakeItEasy / xUnit?

Upvotes: 3

Views: 813

Answers (1)

Blair Conrad
Blair Conrad

Reputation: 242130

I may be oversimplifying, but it sounds like a Strict Fake can help you. Make one, then explicitly allow whatever calls you want.

//Arrange
ICustomContainer fake = A.Fake<ICustomContainer>(x => x.Strict());

// allow just the registrations you want to
A.CallTo(() => fake.Register<IMyInterface, IMyImplementation>()).DoesNothing();

Foo objectUnderTest = new Foo(fake);

//Act
objectUnderTest.Bar();

//Assert
A.CallTo(() => fake.Register<IMyInterface, IMyImplementation>()).MustHaveHappened();

Upvotes: 3

Related Questions