How to register dependencies that are not defined explicitly as Strict using AutoFixture with FakeItEasy?

394 views Asked by At

I use AutoFixture with FakeItEasy when I need to test a class with many dependencies, but I ned to mock only some of them. All the rest of dependencies I prefer mocking with Strict() option of FakeItEasy. In order to make my test more clean, I would like to mock only the dependencies that I want and be able to specify that all the dependencies that do not mock are created with Strict().

In the example below, I would like to be able to remove the two lines of code that create mock of IDependency2, but keep the same behavior: if the class under test accesses any method of IDependency2, an exception would be thrown.

Any idea how to do this?

[TestFixture]
public class AutoTests
{
    [Test]
    public void Test()
    {
        // Arrange
        IFixture fixture = new Fixture().Customize(new AutoFakeItEasyCustomization());

        var dependency1 = fixture.Freeze<IDependency1>();
        A.CallTo(() => dependency1.DoSomething()).Returns(12);

        // I do not want to specify these two lines
        var dependency2 = A.Fake<IDependency2>(s=>s.Strict());
        fixture.Register(() => dependency2);

        // Act
        var classUnderTest = fixture.Create<ClassUnderTest>();
        var actualResult = classUnderTest.MethodUnderTest();

        // Assert
        Assert.That(actualResult,Is.GreaterThan(0));
    }
}

public class ClassUnderTest
{
    private readonly IDependency1 _dependency1;
    private readonly IDependency2 _dependency2;

    public ClassUnderTest(IDependency1 dependency1, IDependency2 dependency2)
    {
        _dependency1 = dependency1;
        _dependency2 = dependency2;
    }

    public int MethodUnderTest()
    {
        return _dependency1.DoSomething() 
            + _dependency2.DoSomething();
    }
}

public interface IDependency1
{
    int DoSomething();
}

public interface IDependency2
{
    int DoSomething();
}
1

There are 1 answers

0
sgnsajgon On BEST ANSWER

As a tradeoff solution, It's quite simple to implement custom ISpecimenBuilder to have all autogenerated fakes as Strict fakes. You can take a look at standard Ploeh.AutoFixture.AutoFakeItEasy.FakeItEasyRelay fakes builder to get idea what's going on behind the curtain. The modified custom builder for Strict fakes is implemented as follows:

    public class FakeItEasyStrictRelay : ISpecimenBuilder
    {
        public object Create(object request, ISpecimenContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            if (!this.IsSatisfiedBy(request))
                return new NoSpecimen(request);

            var type = request as Type;
            if (type == null)
                return new NoSpecimen(request);

            var fakeFactoryMethod = this.GetType()
                .GetMethod("CreateStrictFake", BindingFlags.Instance | BindingFlags.NonPublic)
                .MakeGenericMethod((Type) request);

            var fake = fakeFactoryMethod.Invoke(this, new object[0]);

            return fake;
        }

        public bool IsSatisfiedBy(object request)
        {
            var t = request as Type;
            return (t != null) && ((t.IsAbstract) || (t.IsInterface));
        }

        private T CreateStrictFake<T>()
        {
            return A.Fake<T>(s => s.Strict());
        }
    }

It can be simply register with the following statement:

 IFixture fixture = new Fixture().Customize(
                new AutoFakeItEasyCustomization( new FakeItEasyStrictRelay()));