0

I'm trying to clean up my unit tests by implementing this pattern. Unfortunately, I'm having a problem with my setups, if I try to use It.Is in the matching, so:

public class MockEmployeeExclusionRulesService : Mock<IEmployeeExclusionRulesService>
{
    public MockEmployeeExclusionRulesService MockIsEmployeeExcludedFromSubmissionAsync(FpsFileContentEmployee fpsFileContentEmployee, bool output)
    {
        Setup(x => x.IsEmployeeExcludedFromSubmissionAsync(fpsFileContentEmployee))
            .ReturnsAsync(output);
        return this;
    }
}
_employeeExclusionRulesServiceMock.MockIsEmployeeExcludedFromSubmissionAsync(
    It.Is<FpsFileContentEmployee>(y =>
        y.FpsId == _fpsId &&
        y.PersonOnPayrollId == _personOnPayrollId),
    output: excludeFromSubmission);

When I step through the code, I've found that in the Setup method, fpsFileContentEmployee is null. I've found this answer which I think explains what's going on, but I'm not sure what they mean by "make it an expression typed variable" - what am I making an expression and how do I use it?


Attempt at a minimal reproducible example:

public class InputClass
{
    public string Foo {get; set;}
    public string Bar {get; set;}
}

public interface IMockClass
{
    bool DoTheThing(InputClass inputClass);
}
public class MockMockClass : Mock<IMockClass>
{
    public MockMockClass MockDoTheThing(InputClass inputClass, bool output)
    {
        Setup(x => x.DoTheThing(inputClass))
            .Returns(output);
        return this;
    }
}
[TestFixture]
public class AllTheTests
{
    private readonly MockMockClass _mockClassMock = new ();

    [Test]
    public void DoTheThingTest()
    {
        _mockClassMock.MockDoTheThing(
            It.Is<InputClass>(x =>
                x.Foo == "spam"),
            output: true);
    }
}

I believe that if you debug the test and step through line by line, you'll find that when it gets into MockMockClass.MockDoTheThing(), inputClass will be null.


EDIT: It looks like the problem is trying to assign It.is to a variable - the situation is described further here. Unfortunately, with the pattern I'm using that's fairly unavoidable, so I need to figure out a workaround.

Tam Coton
  • 786
  • 1
  • 9
  • 20

1 Answers1

0

I've managed to find a workaround by creating an overload that takes an expression, like this:

public class MockMockClass : Mock<IMockClass>
{
    public MockMockClass MockDoTheThing(InputClass inputClass, bool output)
    {
        Setup(x => x.DoTheThing(inputClass))
            .Returns(output);
        return this;
    }

    public MockMockClass MockDoTheThing(Expression<Func<InputClass, bool>> inputClassMatch, bool output)
    {
        Setup(x => x.DoTheThing(It.Is(inputClassMatch)))
            .Returns(output);
        return this;
    }
}
[TestFixture]
public class AllTheTests
{
    private readonly MockMockClass _mockClassMock = new ();

    [Test]
    public void DoTheThingTest()
    {
        _mockClassMock.MockDoTheThing(x =>
                x.Foo == "spam",
            output: true);
    }
}

It's not my favourite solution, but it seems to work.

Tam Coton
  • 786
  • 1
  • 9
  • 20