8

我讨厌再次提出这个问题,但我真的很想了解如何通过我的测试来保护某些东西。

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

可以看到,public方法返回void,所以我无法测试public方法调用的结果。我有直接测试的单元测试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);
    }                       
}

编辑 - 根据 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());
}

我不能放过这个;那个编辑很丑。即使我必须创建一个实际的模拟类,这种方法也更干净:

模拟实现:

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

    public void InstallApplication(ApplicationServer server, Application app)
    {
        this.Invoked = true;
    }
}

测试方法:

[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);
}
4

4 回答 4

5

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

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

因此,在这种情况下,您基本上应该创建一个不应InstallApplications安装的应用程序(无论出于何种原因),并在您调用它时验证它是否未安装。

于 2013-02-14T21:43:49.380 回答
3

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

假设它App看起来像:

public class App 
{
    public virtual bool CanBeInstalled {get; set;}
}

ApplicationShouldBeInstalled看起来像:

private bool ApplicationShouldBeInstalled(App app) { return app.CanBeInstalled; }

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

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);
}
于 2013-02-14T21:51:28.890 回答
1

即使公开此方法也不能让您看到它是否被调用。通过将其公开,您可以对其进行测试,但仅此而已。

if如果您以常规方式使用该语句,您的代码会更清晰。那些现在正在删除这条线的程序员甚至会清楚它的目的

public void InstallApplications()
{
    foreach (App app in this._apps)
    {
        if (ApplicationShouldBeInstalled(app)) {
            CommonUtility.Container
                .Resolve<IAppInstaller>()
                .InstallApplication(this, app);
        }
    }                       
}

你也可以让这个方法在调用时增加一个计数器。然后单元测试可以测试这个计数器。

注意:您可以制作此计数器internal并使用InternalsVisibleToAttribute.

更新

下面是这个计数器的实现方式:

public int ApplicationShouldBeInstalled_Count { get; private set; }

public bool ApplicationShouldBeInstalled(App app)
{
    ApplicationShouldBeInstalled_Count++;
    ...
}

然后测试

var sut = new MyInstallerClass();
int oldCount = sut.ApplicationShouldBeInstalled_Count;
sut.InstallApplications();
int newCount = sut.ApplicationShouldBeInstalled_Count;

Assert.AreEqual(oldCount + sut.Apps.Count, newCount);
于 2013-02-14T21:51:20.327 回答
1
public void InstallApplications()
{
    foreach (App app in this._apps.ThatShouldBeInstalled)
    {
        CommonUtility.Container.Resolve<IAppInstaller>().InstallApplication(this, app);
    }                       
}

只是想我会在混合中加入一些横向思维......

小心地把它拿出来,防止它被无意地拿出来。:)

于 2013-02-14T22:05:13.870 回答