2013-02-14 77 views
2

我有单元测试调用ApplicationShouldBeInstalled(app)以确保它正常工作。下面的实际生产代码也会调用该方法,所以它不会无意中安装应用程序。但是,没有任何东西阻止开发人员在检查完成后删除该行代码。而且我的单元测试无法捕捉到,因为测试正在测试ApplicationShouldBeInstalled(app)方法,而不是InstallApplications()方法。移动方法嘲笑?

我不能从我的测试代码中调用InstallApplications(),因为它会尝试安装应用程序。 InstallApplication(app)是同一个类中的一个方法,而不是另一个类,我可以用它来模拟它。有没有办法确保InstallApplications()始终执行该检查?我想我可以将ApplicationShouldBeInstalled(app)移动到另一个类并嘲笑它,但是我只是为了测试/嘲弄而移动代码。有没有更好的办法?

public void InstallApplications() 
{ 
    foreach (App app in this._apps) 
    { 
     if (!ApplicationShouldBeInstalled(app)) { continue; } 

     InstallApplication(app); 
    }      
} 

模拟选项看起来像这样。在运行时,Container会返回真正的实现,并且在运行测试时会返回一个模拟。

public void InstallApplications() 
{ 
    foreach (App app in this._apps) 
    { 
     if (!ApplicationShouldBeInstalled(app)) { continue; } 

     Container.Resolve<IInstaller>().InstallApplication(app); 
    }      
} 
+1

你可以从方法提取一个接口,然后模拟接口? – Robert 2013-02-14 19:52:56

+0

欲了解更多信息,请参阅http://msdn.microsoft.com/en-us/library/fb3dyx26.aspx – 2013-02-14 19:54:04

+0

如果我的理解正确,那是我在我的问题中列出的选项。所以,是的,我可以,但我想知道是否有更好的方法。国际海事组织,所有这些代码都属于它目前所在的班级。我会移动它,如果这是我必须做的才能够测试它。 – 2013-02-14 19:54:22

回答

2

是的,删除控制是否应该从处理安装的代码安装应用程序的策略的代码。这将允许您单独测试这两部分代码,并确信每个代码都在按照您的要求进行操作。我甚至会在这里有3个合作者。控制循环的代码,控制对策略验证的代码,以及执行安装的代码。三件,可独立测试,更容易验证。

foreach (var app in this._apps) 
{ 
    if (!applicationInstallationPolicyProvider.CanInstall(app)) // can be mocked away 
    { 
      continue; 
    } 

    applicationInstaller.Install(app); // can also be mocked away 
} 

我认为你的关键是当你在问题中说“你不能在测试中运行安装代码”。但是,对于您确认实际上将在需要时调用安装代码应该很重要。这应该是足够的动机已经试图孤立它,不管你是否采取我可能喜欢的程度。

+0

这符合我刚刚添加到我的问题,所以我相信我是在正确的道路上。谢谢! – 2013-02-14 20:01:55

+2

我认为你的关键是当你在问题中说“你不能在测试中运行安装代码”。但是,验证循环实际将*调用安装代码对你来说应该很重要。已经有足够的动机来尝试隔离它。 – 2013-02-14 20:04:43

+0

同意!现在就做。谢谢! – 2013-02-14 20:13:45

1

当你将它提取到一个接口时,你并不真正删除属于该类的代码。您正在要求班级实施成员。使用接口的一个主要好处是它允许你嘲笑它们,所以你不会真正改变功能。你嘲笑界面,然后你确认一个特定的方法实际上正在做你期望的操作。

在旁边注意它也允许您使用依赖注入,以便您不在内存中不断创建对象的实例。

+0

同意。谢谢。 – 2013-02-14 20:02:34