Spoof data like a pro

Staging

Let's consider a small Student class

    public class Student
    {
       public string Name { get; set; }
       public int Age { get; set; }
       public bool HasLicense { get; set; }
    }

and the Security class, which checks licenses

    public class Security
    {
       public bool CheckLicense(Student student)
       {
          return student.HasLicense;
       }
    }

We need to test the functionality of the CheckLicense method.

Standard test

Based on the experience of previous article, we could write something like

    [Fact]
    public void CheckLicense_Success()
    {
       var student = FakeFactory.Fixture.Create<Student>();
     //
       var result = security.CheckLicense(student);
     //
       Assert.True(result == student.HasLicense);
    }

Looks good, but what if we complicate the situation and include a service in the scheme that issues student status according to the date of the request?

    public interface IStudentLicenseStore
    {
       bool GetLicense(string name, DateTime date);
    }
    
    public class Security
    {
       private readonly IStudentLicenseStore _store;
   
       public Security(IStudentLicenseStore store)
       {
          _store = store;
       }
       public bool CheckLicense(Student student, DateTime date)
       {
          return _store.GetLicense(student.Name, date);
       }
    }

Of course, bool looks strange here, but such a simplified model will do for our purposes. So how will our test change?

   [Fact]
    public void CheckLicense_Success()
    {
       var student = FakeFactory.Fixture.Create<Student>();
       var serviceResult = FakeFactory.Fixture.Create<bool>();
       var date = FakeFactory.Fixture.Create<DateTime>();
       _store.Setup(s => s.GetLicense(student.Name, date)).Returns(serviceResult);
       //
       var result = security.CheckLicense(student, date);
       //
       Assert.True(result == serviceResult);
    }

There is more and more input data and the test becomes bulky, although, in reality, the lines with the declaration of variables do not significant for us. Can this code be simplified?

AutoMoqDataAttribute

The Theory and AutoData attributes could come to the rescue, they themselves can provide a fake of all the data we need, but in this case we lose the ability to use the FakeFactory class and configure fakes at our discretion. But these settings will be very useful to us in future articles, it is clearly not worth refusing them)

Let's create the AutoMoqDataAttribute class in the test project

    public class AutoMoqDataAttribute : AutoDataAttribute
    {
        public AutoMoqDataAttribute() : base(FakeFactory.Fixture)
        {
        }
    }

As you can see, this class is a lightweight wrapper over the AutoDataAttribute and its only task is to pass our fake settings, which will be very useful to us in the future.

Let's change our test

    [Theory, AutoMoqData]
    public void CheckLicense_Success(Student student, bool serviceResult, DateTime date)
    {
       _store.Setup(s => s.GetLicense(student.Name, date)).Returns(serviceResult);
       //
       var result = security.CheckLicense(student, date);
       //
       Assert.True(result == serviceResult);
    }

The test looks much neater and is not overloaded with non-essential data, win?

InlineAutoDataAttribute

When writing tests, sometimes there are situations when automatically generated fakes do not meet the requirements of the application, so Student may have a Phone field that is significant for the method under test. Normally we could use InlineData, but the AutoMoqDataAttribute blocks using of InlineData and will not allow the specified values.

In order to solve this problem, let's add another support class.

    public class InlineAutoMoqDataAttribute : InlineAutoDataAttribute
    {
        public InlineAutoMoqDataAttribute(params object[] objects) : base(new AutoMoqDataAttribute(), objects)
        {
        }
    }

And again, this is a wrapper over a base class of AutoFixture, two points are important for us.

  1. Passing AutoMoqDataAttribute will allow the desired FakeFactory instance to be used.
  2. Passing InlineData parameters. With this approach, a pass will be performed on all incoming test parameters; the zero parameter will be taken from the zero index of objects, the first from the first, and so on. If objects ends and parameters are still required, AutoMoqDataAttribute will take effect and generate random fakes.

As a result, our test will look something like this:

    [Theory]
    [InlineAutoMoqData("123456789")]
    public void CheckLicense_Success(string phone, Student student, bool serviceResult, DateTime date)
    {
       _store.Setup(s => s.GetLicense(student.Name, date)).Returns(serviceResult);
       //
       var result = security.CheckLicense(student, date);
       //
       Assert.True(result == serviceResult);
    }

Note that AutoMoqDataAttribute is not used directly in this case.

Conclusion

Using of the two described classes should, in my opinion, be included into the standard for organizing testing code, that is contributing to improved readability and simplification of writing tests.