5

In .NET Core for unit testing, I'm using Xunit, Moq, and Autofixture. But even with them, I see that my unit tests become complicated and take time.

Maybe someone could tell me if there are any ways to make this test smaller?

[Fact]
public async Task Verify_NotAuthorised_NoServiceSendInvoked()
{
    // Arrange
    var fixture = new Fixture()
        .Customize(new AutoMoqCustomization());

    var sut = fixture.Create<VerificationService>();

    var mockApiBuilder = fixture.Freeze<Mock<IApiEntityBuilder>>();
    //init mocked mockSendServiceOne, so later I could check if it was invoked or not
    var mockSendServiceOne = fixture.Freeze<Mock<ISendServiceOne>>();

    mockApiBuilder.Setup(x => x.Verification(It.IsAny<string>(), It.IsAny<string>()))
        .Returns(fixture.Create<VerificationEntity>());

    var call = fixture.Freeze<Mock<ISendServiceTwo>>();
    call.Setup(x => x.IsSuccessful()).Returns(false);

    // Act
    await sut.Verify(fixture.Create<string>(), fixture.Create<string>());

    // Assert
    mockSendServiceOne.Verify(x => x.Call(It.IsAny<SendServiceOneEntity>()), Times.Never);
}

The testing method itself

public async Task<CreatedEntity> Verify(string dataOne, string dataTwo)
{
   await _someCaller.Call(_apiEntityBuilder.Verification(dataOne, dataTwo));
   _someCaller.CreatePayment();

   if (!_someCaller.IsSuccessful()) return _someCaller.CreatedEntity;

   await mockSendServiceOne.Call(_apiEntityBuilder.Call(_someCaller.CreatedEntity.SpecificData));

   return _someCaller.CreatedEntity;
}

Here I am testing if isSuccessful() returns fasle then no mockSendServiceOne.Call should be invoked.

Could someone give me some feedback on how to write a better unit tests. Because only for this small check of code I had to write a lot of code to test it.

5
  • How much code for unit test would be "good" amount of code, so you wouldn't worried about it? Commented Oct 2, 2019 at 8:16
  • Maybe I say in other words, this test to write took me about 25-30min and is it okay? So I would like to get some feedback from others, is it a good test or should investigate in my code design or unit test structure. For instance, I am trying to keep my service classes containing max 2-3 dependencies so my test would not be heavy. Commented Oct 2, 2019 at 8:23
  • Does writing second test took 25-30 minutes also or less? Commented Oct 2, 2019 at 9:40
  • Well, the second test took me definitely less, 2-5min. Commented Oct 2, 2019 at 10:07
  • *Testing the same method but different outputs/states, to be more clearly Commented Oct 2, 2019 at 12:23

1 Answer 1

5

You can use AutoData Theories. (Links to a great post by Mark Seeman about this exact situation).

In short AutoFixture has a built in attribute called AutoData which you can inherit from and then customize the fixture with the AutoMoqCustomization.

You decorate your testmethod ([Theory]) with this attribute, and now autofixture automagically will generate any parameter you specify for your testmethod.

When you would use the Freeze() method to generate an item, you put the [Frozen]attribute in front of the parameter.

Here is an example of how to do it:

public class TheTests
{
    [Theory]
    [AutoDomainData]
    public void Verify_WhatWeWannaTest_CallsTheMethodOnTheDependency([Frozen] Mock<ITheDependency> dependency, WhatWeWannaTest sut)
    {
        // Act
        sut.CallTheDependency();

        // Assert
        dependency.Verify(x => x.TheMethod());
    }
}

// Create a AutoData attribute customized with Moq
public class AutoDomainDataAttribute : AutoDataAttribute
{
    public static IFixture FixtureFactory()
    {
        var f = new Fixture();
        // I like members of interfaces to be configured, so i set it her
        f.Customize(new AutoMoqCustomization { ConfigureMembers = true });
        return f;
    }

    public AutoDomainDataAttribute() : base(FixtureFactory) { }
}

// Simple class we can test
public class WhatWeWannaTest
{
    private readonly ITheDependency _theDependency;

    public WhatWeWannaTest(ITheDependency theDependency) { _theDependency = theDependency; }

    public void CallTheDependency()
    {
        _theDependency.TheMethod();
    }
}

// Simple dependency for WhatWeWannaTest
public interface ITheDependency
{
    int TheMethod();
}
Sign up to request clarification or add additional context in comments.

4 Comments

What if I want to declare a fake object with some specific fields using AutoDataAttribute? Because in the method scope I can't change a fixture instance. Doesn't it limit all the benefit giving from autofixture?
Of course, I can change object's property by myself without any fixture after, but still, I see that not all functionality will be available for me in a simple way using attribute
If you want your mocks to have a certain default behaviour across tests, I would customize the types in the FixtureFactory. When I need to do a little more advanced stuff with the fixture (which is seldom) I ask for an instance of the fixture e.g.: TestMethod(IFixture fixture). Then I get a customized fixture, from the FixtureFactory. @Andrius
I didn't know that it's possible to get IFixture instance from the method's parameters. Great!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.