C# 嵌套方法的单元测试

C# 嵌套方法的单元测试,c#,unit-testing,mocking,moq,C#,Unit Testing,Mocking,Moq,假设我有这样的服务: public class MyService : IMyService { public void DoStuff(IDependency dependency, string value) { dependency.SomeMethod(value, true); DoOtherStuff(dependency); } public void DoOtherStuff(IDependency depende

假设我有这样的服务:

public class MyService : IMyService
{
    public void DoStuff(IDependency dependency, string value)
    {
        dependency.SomeMethod(value, true);
        DoOtherStuff(dependency);
    }

    public void DoOtherStuff(IDependency dependency)
    {
        // do some stuff
    }
}
现在,当单元测试
MyService
时,我可以很容易地模拟依赖关系,并测试依赖关系是否正确使用:

public void MyServiceTest()
{
    // Arrange 
    var mockDependency = new Mock<IDependency>();
    mockDependency.Setup(m => m.SomeMethod());
    var service = new MyService();

    // Act
    service.DoStuff(mockDependency.Object, "value");

    // Assert
    mockDependency.Verify(v => v.SomeMethod(), Times.Once);
}
public void myservice测试()
{
//安排
var mockDependency=new Mock();
mockDependency.Setup(m=>m.SomeMethod());
var service=newmyservice();
//表演
service.DoStuff(mockDependency.Object,“value”);
//断言
验证(v=>v.SomeMethod(),Times.Once);
}

如何测试服务是否调用
DoOtherStuff
?或者这是一种糟糕的模式?正确的方法是什么?

对于另一个类,您将使用moq,如前所述

但是,该类正在测试中,我认为您不应该在测试中分离这两个方法,原因类似于您不测试私有方法。归根结底,如果代码经过重构,在测试失败时不会调用第二个方法。不,公共API不受影响


最好像您现在所做的那样,对调用DoOtherStuff时的依赖性做出断言。

对于另一个类,您将使用moq,如前所述

但是,该类正在测试中,我认为您不应该在测试中分离这两个方法,原因类似于您不测试私有方法。归根结底,如果代码经过重构,在测试失败时不会调用第二个方法。不,公共API不受影响


最好像您现在所做的那样,对DoOtherStuff所称的依赖性进行断言。

您不应该关心单元测试,只要特定的公共功能满足契约,它是如何实现的

注意:上面的“public”一般用于“外部可用”,通常与C#
public
一致,但有时您希望/必须将其他方法标记为public,即使它实际上不是外部合同的一部分


如果您确实必须测试调用了
DoOtherStuff
,您可以将该方法设置为虚拟的
并使用测试实现,该实现提供了自己的版本,以某种方式通知您调用(可能Moq也可以为您构建一个).

您不应该关心单元测试,只要特定的公共功能满足其契约,它是如何实现的

注意:上面的“public”一般用于“外部可用”,通常与C#
public
一致,但有时您希望/必须将其他方法标记为public,即使它实际上不是外部合同的一部分

如果您确实必须测试调用了
DoOtherStuff
,您可以将该方法设置为虚拟的
并使用测试实现,该测试实现提供了自己的版本,以某种方式通知您调用(可能Moq也可以为您构建一个)。

作为注释(故意不在答案正文中加入),如果这些方法是虚拟的,您可以在测试中重写它们。然而,在大多数情况下,我并不认为这是一件非常有帮助的事情。我认为我们之所以关心某件事被称为“时代”的核心是因为它是类与类之间的互动。还有
Delegate.CreateDelegate(元数据等)
。也有黑暗面的方式,但我并不十分熟悉。作为说明(故意不在答案正文中),如果方法是虚拟的,您可以在测试中重写它们。但是,我认为在大多数情况下,这不是一件非常有用的事情。我认为我们关心的核心是什么东西会被多次调用。一次是因为它是类之间的交互。还有
Delegate.CreateDelegate(元数据等
。黑暗面也有出路,但我并不十分熟悉。