如何验证传递给函数的操作被调用?

时间:2015-02-18 12:34:54

标签: unit-testing moq

我正在努力使用Moq进行单元测试,以便将BL与DataAccess隔离开来。请考虑以下业务逻辑:

public class MyBusinessLogic
{

private IDataAccess _dataAccess;

public MyBusinessLogic(IDataAccess dataAccess)
{
    _dataAccess = dataAccess;
}

public string SendEmail(string username)
{
    var emailAddress = _dataAccess.RunCommand<CommandDetails>("GetEmailAddressForUser", AddParametersToGetEmailAddress, new CommandDetails{Username = username});

    // do some send email stuff...

    return string.Concat("Email sent to ", emailAddress);
}

private void AddParametersToGetEmailAddress(IDbCommand command, CommandDetails details)
{
    var p = command.CreateParameter();
    p.ParameterName = "username";
    p.Value = details.Username;
    command.Parameters.Add(p);
}
}

一组参数详情

public class CommandDetails
{
    public string Username {get; set;}
}

和DataAccess接口

public interface IDataAccess
{
    string RunCommand<TCommandDetails>(string command, Action<IDbCommand, TCommandDetails> addParameters, TCommandDetails details);
}

我有一个测试

var username = @"joebloggs";

var mock = new Mock<IDataAccess>();
mock.Setup(x => x.RunCommand<CommandDetails>(
    It.Is<string>(commandString => commandString == "GetEmailAddressForUser"),
    It.IsAny<Action<IDbCommand,CommandDetails>>(),
    It.Is<CommandDetails>(details => details.Username == username)))
.Returns("joebloggs@hotmail.com");

var businessLogic = new MyBusinessLogic(mock.Object);   

var message = businessLogic.SendEmail(username);

Assert.AreEqual("Email sent to joebloggs@hotmail.com", message);

这很棒,它证明SP已被调用,并且电子邮件已发送到返回的地址。

但是,它并不能证明调用了AddParametersToGetEmailAddress方法。我们知道所有人都没有参数调用SP。

如何修改我的设置以仅返回在命令上设置username参数的电子邮件地址?

1 个答案:

答案 0 :(得分:1)

AddParametersToGetEmailAddress不会被调用,因为您正在嘲笑可以调用它的方法(RunCommand)。

要实现您想要的(我认为),您可以向将调用您的操作的方法设置添加回调,然后检查CommandDetails之后的值:

var mockDbCommand = new Mock<IDbCommand>();

mock.Setup(x => x.RunCommand<CommandDetails>(
           It.Is<string>(commandString => commandString == "GetEmailAddressForUser"),
           It.IsAny<Action<IDbCommand,CommandDetails>>(),
           It.Is<CommandDetails>(details => details.Username == username)))
    .Callback<string, Action<IDbCommand,CommandDetails>, CommandDetails((s,a,d) => WrapAction(mockDbCommand.Object, d, a))
    .Returns("joebloggs@hotmail.com");

...

void WrapAction(IDbCommand dbCommand, CommandDetails commandDetails, Action<IDbCommand,CommandDetails> action)
{
    // Call the action, which will be AddParametersToGetEmailAddress
    action(dbCommand, commandDetails);

    // Assert that dbCommand has the username parameter
}

请注意,您需要创建mockDbCommand才能转到操作。