简体   繁体   中英

c# - Assert Expressions

I have an 'Example' class and I would like to create unit test for it. Take a look on my classes below:

public class Example 
{
    private readonly Calculator _calculator;

    public Example(ICalculator calculator)
    {
        _calculator = calculator;
    }

    public void Calculate()
    {
        _calculator.Execute(operation => operation.Subtract());
    }
}

public interface IOperation { 
    void Sum();
    void Subtract();
}

public inferface ICalculator { 
    void Execute(Action<IOperation> action);
}

public class Calculator {
    public void Execute(Action<IOperation> action){}
}

What I want is to create a Unit Test class to verify that my method from Example class Calculate calls the _calculator.Execute passing as parameter the operation.Subtract() . Is it possible?

I know how to mock my ICalculator and verify that Execute is being called once, but I have no idea how to validade if Execute method was called using operation.Subtract() as parameter instead of operation.Sum() .

I am using NUnit to create my unit tests. Here you can see how my unit test class is at the moment:

[TestFixture]
public class ExampleTests 
{
    [Test]
    public void Test1()
    {
        var calculator = new Mock<ICalculator>();
        var subject = new Example(calculator.Object);

        subject.Calculate();

        calculator.Verify(x => x.Execute(It.IsAny<Action<IOperation>>()), Times.Once);
    }
}

Hope someone can understand my english, sorry about that.

You're passing anonymous delegate operation => operation.Subtract() to _calculator.Execute - so you cannot construct it later when asserting for argument.

You can get around it by doing this:

    public class Example 
    {
        private readonly ICalculator _calculator;

        public Example(ICalculator calculator)
        {
            _calculator = calculator;
        }

        public Action<IOperation> Subtract = op => op.Subtract();

        public Action<IOperation> Add = op => op.Sum();

        public void Calculate()
        {
            _calculator.Execute(Subtract);
        }
    }

And asserting like this (ommiting 2nd param defaults to Once):

calculator.Verify(x => x.Execute(subject.Subtract));

However this looks like convoluted design in order to be able to write a test.

You cannot directly verify what lambda was passed but you can go around it by actually invoking said lambda with yet another mock:

var calculator = new Mock<ICalculator>();
var operation = new Mock<IOperation>();
// when calculator's Execute is called, invoke it's argument (Action<IOperation>)
// with mocked IOperation which will later be verified
calculator
    .Setup(c => c.Execute(It.IsAny<Action<IOperation>>()))
    .Callback<Action<IOperation>>(args => args(operation.Object));
var example = new Example(calculator.Object);

example.Calculate();

calculator.Verify(c => c.Execute(It.IsAny<Action<IOperation>>()));
operation.Verify(o => o.Subtract());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM