如果我们不验证使用单元测试调用私有方法,我们如何验证它们是否被调用?

Bob*_*orn 8 c# testing mstest moq

我讨厌再次提起这件事,但我真的想了解如何用我的测试保护一些东西.

我有一个公共方法(下面),在调用另一个实际采取某些操作的方法之前调用私有方法.我想确保不会删除对私有方法的调用,因为这可能是灾难性的.我已经做了一些研究,在这里,这里,在这里,他们都说不要测试私有方法.我想,我可以理解,但是我如何防止删除这行代码

如您所见,public方法返回void,因此我无法测试公共方法调用的结果.我有ApplicationShouldBeInstalled()直接测试的单元测试.

public void InstallApplications()
{
    foreach (App app in this._apps)
    {
        // This is the line of code that can't be removed. How can I make
        // sure it doesn't get removed?
        if (!ApplicationShouldBeInstalled(app)) { continue; }

        // This simply can't run unless it passes the above call.
        CommonUtility.Container.Resolve<IAppInstaller>().InstallApplication(this, app);
    }                       
}
Run Code Online (Sandbox Code Playgroud)

编辑 - 根据JerKimball的回答,我选择了这个.

基本上,我只使用Mock对象(来自Moq),然后验证其方法被调用了预期的次数.

[TestMethod()]
public void ApplicationShouldBeInstalledTest_UseCase13()
{
    var mockAppInstaller = new Mock<IAppInstaller>();
    mockAppInstaller.Setup(m => m.InstallApplication(It.IsAny<ApplicationServer>(),
        It.IsAny<Application>()));
    CommonUtility.Container.RegisterInstance<IAppInstaller>(mockAppInstaller.Object);

    // Actual test code here

    appServer.InstallApplications();
    mockAppInstaller.Verify(x => x.InstallApplication(It.IsAny<ApplicationServer>(),
        It.IsAny<Application>()), Times.Never());
}
Run Code Online (Sandbox Code Playgroud)

我不能放过这个; 编辑只是丑陋.即使我必须创建一个实际的模拟类,这种方法更清晰:

模拟实现:

public class MockAppInstaller : IAppInstaller
{
    public bool Invoked { get; set; }

    public void InstallApplication(ApplicationServer server, Application app)
    {
        this.Invoked = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试方法:

[TestMethod()]
public void ApplicationShouldBeInstalledTest_UseCase14()
{
    MockAppInstaller mockAppInstaller = new MockAppInstaller();
    CommonUtility.Container.RegisterInstance<IAppInstaller>(mockAppInstaller);

    // Actual test code here

    appServer.InstallApplications();
    Assert.AreEqual(true, mockAppInstaller.Invoked);
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 5

我想确保不会删除对私有方法的调用,因为这可能是灾难性的.

听起来应该很容易.灾难很容易发现.因此,运行一个调用公共方法的测试,并检查是否发生了任何灾难性事件.私有方法中防止灾难的代码实际上是运行公共方法的可见副作用......而它是由私有方法调用引起的这一事实是一个实现细节.

因此,在这种情况下,你应该基本上创造出一个应用程序不应该被安装(无论何种原因),并验证,当你调用InstallApplications没有安装.


Jer*_*all 3

这是一个可能的选择...当然,这非常简单,但稍作修改可能适用于您的情况;

假设App看起来像:

public class App 
{
    public virtual bool CanBeInstalled {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

看起来ApplicationShouldBeInstalled像:

private bool ApplicationShouldBeInstalled(App app) { return app.CanBeInstalled; }
Run Code Online (Sandbox Code Playgroud)

您可以编写一个“通过预期操作确认”的单元测试,如下所示:

void Main()
{
    var sut = new ThingToTest();    

    var mockApp = new Mock<App>();
    var wasCanBeInstalledChecked = false;
    mockApp
       .SetupGet(app => app.CanBeInstalled)
       .Callback(() => wasCanBeInstalledChecked = true);

    // of course, whatever you'd do here to get an app into this class
    sut.AddApp(mockApp.Object);

    sut.InstallApplications();
    Debug.Assert(wasCanBeInstalledChecked == true);
}
Run Code Online (Sandbox Code Playgroud)