我是单位测试的新手,所以请原谅我,如果我无法正确解释这个问题。我正在读一本书"单元测试艺术第2版"并尝试在我的项目中实现单元测试。在使用模拟进行测试时(使用NSubstitute作为模拟框架),我目前陷入困境或困惑。
以下是我的情景:
我有两个接口ICommand
和IUser
public interface ICommand
{
string execute();
}
public interface IUserCalendar
{
string LoadCalendar();
}
我有一个实现LoadCalendar
的课程ICommand
:
public class LoadCalendar : ICommand
{
private IUserCalendar user;
public string execute()
{
return this.user.LoadCalendar();
}
public LoadCalendar(IUserCalendar obj)
{
this.user = obj;
}
}
ViewCalendar
实施IUserCalendar
:
public class Viewer : IUserCalendar
{
public string LoadCalendar()
{
return "Viewer Load Calendar Called";
}
}
使用代理类我正在调用特定请求的命令。 (这里我只为一个用户查看器显示一个请求LoadCalendar
,但我有更多命令和更多用户)
我的客户端有一个调用者对象,可以为特定用户调用该命令。
public class Client
{
public Client()
{ }
public string LoadCalendar(ICommand cmd)
{
Invoker invoker = new Invoker(cmd);
return invoker.execute();
}
}
现在我想测试客户端类,当它调用特定用户时,它应该返回正确的对象或消息。
[Test]
public void client_Load_Calendar_Administrator()
{
IUserCalendar calanedar = Substitute.For<IUserCalendar>();
ICommand cmd = Substitute.For<ICommand>(calanedar);
Client c = new Client();
c.LoadCalendar(cmd, calanedar).Returns(Arg.Any<string>());
}
我不知道自己哪里做错了,而且发生了错误。
NSubstitute.Exceptions.SubstituteException:替换接口时无法提供构造函数参数。
非常感谢任何帮助。对不起,很长的问题。
答案 0 :(得分:3)
您获得的错误:
替换接口时无法提供构造函数参数。
告诉你到底出了什么问题。
你在这里传递构造函数参数:
ICommand cmd = Substitute.For<ICommand>(calanedar);
当然,接口永远不会有构造函数。您尝试与ICommand界面进行交互,就好像它是您具体的LoadCalendar
实现一样。
此外,为了能够对一个类进行单元测试,你总是希望有一个默认的(无参数)构造函数。许多模拟框架实际上需要这个。
在这种情况下,您应该测试具体类并模拟/替换它使用的类。
要么是这样,要么只用ICommand
替换它来返回预设(字符串)值。然后,您可以继续验证使用您的命令的代码,实际调用它和/或使用它返回的值执行正确的操作。
举例说明:
[Test]
public void client_Load_Calendar_Administrator()
{
// You are substituting (mocking) the IUserCalendar here, so to test your command
// use the actual implementation
IUserCalendar calendar = Substitute.For<IUserCalendar>();
ICommand cmd = new LoadCalendar(calendar):
// Let the IUserCalendar.LoadCalendar() return a certain string
// Then Assert/Verify that cmd.Execute() returns that same string
}
这是单元测试的重点:通过模拟所有依赖项来测试最小的功能。否则它就是集成测试。
测试您的客户:
[Test]
public void client_Load_Calendar_Administrator()
{
ICommand cmd = Substitute.For<ICommand>();
Client c = new Client();
// Let your command return a certain string
// Then verify that your calendar returns that same string
}
编辑:如果您有兴趣,the method in NSubstitute that throws this exception:
private void VerifyNoConstructorArgumentsGivenForInterface(object[] constructorArguments)
{
if (constructorArguments != null && constructorArguments.Length > 0)
{
throw new SubstituteException("Can not provide constructor arguments when substituting for an interface.");
}
}
他们非常清楚:无论如何都没有接口替换的构造函数参数。