【问题标题】:Using Nsubstitute for mocking but getting an error使用 Nsubstitute 进行模拟但出现错误
【发布时间】:2015-04-06 15:44:52
【问题描述】:

我是单元测试的新手,如果我无法正确解释这个问题,请原谅我。我正在阅读一本书“单元测试的艺术第 2 版”并尝试在我的项目中实施单元测试。我目前在使用模拟(使用 NSubstitute 作为模拟框架)进行测试时遇到困难或困惑。

这是我的场景:

我有两个接口ICommandIUser

 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 : 替换接口时无法提供构造函数参数。

非常感谢任何帮助。抱歉,问题太长了。

【问题讨论】:

  • 感谢您编辑 Marc。如果你认识能回答这个问题的人,请转发给他。

标签: c# asp.net unit-testing mocking nsubstitute


【解决方案1】:

你得到的错误:

替换接口时不能提供构造函数参数。

准确地告诉你出了什么问题。

你在这里传入构造函数参数:

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.");
    }
}

他们对此非常清楚:无论如何,接口替代都没有构造函数参数。

【讨论】:

  • 您能否提供有关集成测试的更多详细信息?任何链接或任何书籍参考都非常感谢
  • 此链接可能对您来说很有趣:stackoverflow.com/questions/5357601/…。抱歉,我无法为您提供工作代码示例 - 我不熟悉 NSubstitute,我个人使用的是 Moq。所以我不知道如何完成我试图解释的确切语义。如果您愿意,我可以提供一个使用 Moq 和 XUnit 完成的更完整示例吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多