C# 模拟数据访问器
我正在努力学习如何与NUnit和IoC一起使用Moq (我在BitBucket中有我的完整项目,但不确定如何共享…) 我有一个逻辑方法(登录),我正在尝试测试。它接受一个请求对象(具有用户名、密码和IP地址)。如果用户名和/或密码为空,则逻辑将返回失败状态,并且不会转到数据访问层 所以我创建了一个单元测试来测试这一点。 (这是我第一次尝试嘲弄……)C# 模拟数据访问器,c#,unit-testing,inversion-of-control,moq,C#,Unit Testing,Inversion Of Control,Moq,我正在努力学习如何与NUnit和IoC一起使用Moq (我在BitBucket中有我的完整项目,但不确定如何共享…) 我有一个逻辑方法(登录),我正在尝试测试。它接受一个请求对象(具有用户名、密码和IP地址)。如果用户名和/或密码为空,则逻辑将返回失败状态,并且不会转到数据访问层 所以我创建了一个单元测试来测试这一点。 (这是我第一次尝试嘲弄……) public void NotNull\u返回\u True() { //安排 var请求=新登录请求{IPAddress=“1.1.1.1”,U
public void NotNull\u返回\u True()
{
//安排
var请求=新登录请求{IPAddress=“1.1.1.1”,Username=“dummy”,Password=“dummy”};
var response=newloginresponse{Request=Request,Success=true,Message=”“,UserID=1};
//设置moc数据访问器,因为我们不想访问具体的数据访问器。
var MockedDataAccess=new Mock();
//设置它的返回值
MockedDataAccess.Setup(x=>x.Login(请求))。返回(响应);
//使用Moc数据访问器实例化我们正在测试的逻辑类。
var逻辑=新业务逻辑(MockedDataAccess.Object);
//表演
var result=logic.Login(新的LoginRequest{Password=“dummy”,Username=“dummy”,IPAddress=“1.1.1”});
//断言
断言。相等(正确、结果、成功);
}
这在断言上失败,因为“result”为NULL
我可能做错了很多。例如,我不确定为什么我需要在顶部设置请求和响应对象,但因为我找到的所有示例都是“string”和“int”输入,似乎我无法使用它
有人能帮我理解一下吗?在断言中得到NULL的结果有什么不对?我一步一步地完成,代码按预期执行。但是结果为null,因为我从未调用过数据访问器(它使用了mock)
编辑:
啊,
//设置它的返回值
MockedDataAccess.Setup(x=>x.Login(It.IsAny())。返回(响应);
这解决了问题。我不知道为什么,所以如果你能帮助我理解并重构它,让它看起来像一个有经验的Moq/UnitTester所期望的那样,那将是非常有用的。即使你的
请求
对象的属性值与你传递给var result=logic.Login的属性值相同,Username=“dummy”,IPAddress=“1.1.1.1”})
,它们是不同的对象,因此您尝试使用MockedDataAccess.Setup(x=>x.Login(request)).Returns(response)返回的值代码>未返回
改变
var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" });
到
它使用MockedDataAccess.Setup(x=>x.Login(it.IsAny()).Returns(response)的原因
是因为现在您说的是“当调用MockedDataAccess.Login
时,其参数值为any,返回response
”
关于问题的第二部分,需要设置请求和响应对象的原因是,默认情况下,对模拟对象调用的任何方法都将返回null。下面列出的BusinessLogic.Login
方法将返回dataAccess.Login()
的值。由于dataAccess
是一个模拟,因此dataAccess.Login()
方法将返回null,除非您另行通知
public LoginResponse Login(LoginRequest request)
{
// Basic validation
if (request == null)
return new LoginResponse
{
Success = false,
Message = "Empty Request"
};
if (string.IsNullOrEmpty(request.Username) || string.IsNullOrEmpty(request.Password))
return new LoginResponse
{
Success = false,
Message = "Username and/or password empty"
};
// This is returning null since dataAccess is a mock
return dataAccess.Login(request);
}
你说你认为你做错了很多,但是你设置测试的方式和我差不多。我唯一要改变的事情(除了修复上面描述的设置
方法)是为测试使用UnitOfWork\u StateUnderTest\u ExpectedBehavior命名模式。例如,Login\u ValidLoginRequest\u应该返回validloginResponse()
此代码的问题
var result=logic.Login(新登录请求{Password=“dummy”,Username=“dummy”,IPAddress=“1.1.1.1”})
在Login
方法的实现中,这被称为
dataAccess.Login(请求)
这意味着您必须为方法Login
设置DataAccess
的mock,否则mock什么也不做。如果模拟是假的,则需要进行设置,以便按照您需要的方式工作。在这种情况下,@Ben Rubin的答案是绝对正确的
当mock设置为这样时
MockedDataAccess.Setup(x=>x.Login(请求)).Returns(响应)
然后,有必要使用与设置数据访问Login
方法中使用的请求完全相同的请求对象调用测试中的方法,因为否则mock将充当not setup。在这里,您基本上是说“当使用此请求调用DataAccess登录时,将返回该响应”
但是当mock是这样设置的时候
MockedDataAccess.Setup(x=>x.Login(It.IsAny())。返回(响应)
然后它就工作了,因为这里的Login
设置为任何LoginRequest
。因此,在这种情况下,无论使用什么请求,mock都将返回响应。嗯
以下是有关登录方法的更多信息?它是否会调用您的IDataAccess
依赖项上的方法,如果这些方法返回null,则返回null?@BenRubin-我添加了一个Bitbucket链接,因此您可以查看所有这些方法并进行克隆。但基本上,如果有空值发送到BL层,它将计算并返回一个成功标志为False的响应对象。它不应该返回空对象。谢谢@BenRubin-这一切都很有意义,在我的学习道路上帮助了我,并提供了一些验证。谢谢
var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" });
var result = logic.Login(request);
public LoginResponse Login(LoginRequest request)
{
// Basic validation
if (request == null)
return new LoginResponse
{
Success = false,
Message = "Empty Request"
};
if (string.IsNullOrEmpty(request.Username) || string.IsNullOrEmpty(request.Password))
return new LoginResponse
{
Success = false,
Message = "Username and/or password empty"
};
// This is returning null since dataAccess is a mock
return dataAccess.Login(request);
}