我正在努力使用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参数的电子邮件地址?
答案 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
才能转到操作。