2017-06-02 73 views
1

我有一些测试代码正在初始化一些应该在开始时只做一次的成员。这就是为什么我用的构造:单元测试的构造函数运行两次

[TestFixture] 
public class MyTestClass 
{ 
    private readonly IUnitTestGeometryProvider m_GeometryProvider; 


    public MyTestClass() 
    { 
     // do some heavy init-op 
    } 

    private IEnumerable<TestCaseData> TestCases() 
    { 
     yield return new TestCaseData(this.m_GeometryProvider.GetPolyline()) 
      .Throws(typeof(ArgumentException)); 
    } 

    [TestCaseSource("TestCases")] 
    public double Check_GetReducedArea_For_Invalid_Arguments(IGeometry theGeom) 
    { 
     return theGeom.GetReducedArea(); 
    } 
} 

我知道这个约定的使用FixtureSetup -attribute初始化测试,例如从this question on SO。但是我注意到方法TestCases在用该属性标记的方法之前执行,所以当评估不同的测试用例时碰到NullReferenceException,因为m_GeometryProvider目前为null

所以我调试了我的代码并在构造函数中设置了一个断点。我注意到,它在任何测试甚至运行之前执行了两次。我假定每个测试用例都有自己的MyTestClass实例,但由于我有三个不同的测试用例,并且构造函数运行两次,所以这并不能解释它。

由于初始化很重,我只想执行一次。有没有办法保证这一点?我想避免一个static成员,因为它经常吸引同事大量使用其他static成员,因为已经有成员。此外,我认为test-init只针对我的MyTestClass的一个实例,而不是类本身 - 假设只有一个实例。

我正在使用NUnit 2.5.10。

+0

不要使用构造函数进行初始化。使用'TestFixtureSetup'属性进行大量初始化,而不是构造函数。每个测试初始化​​方法都用'SetUp'属性标记。 BTW 2.5.10很旧。目前的版本是3.7 –

+0

@PanagiotisKanavos我已经解释了为什么这对我不起作用。问题在于,使用该属性后,标记为该方法的方法在* TestCases方法后运行很远,导致后者运行到NRE。 – HimBromBeere

+1

@PanagiotisKanavos它会引发错误,因为TestCases在安装之前运行 –

回答

4

基本上,NUnit保留在任何需要时都可以构建您的夹具对象的权利,而且它可以随时根据需要进行构建。因此,您应该避免在构造函数中进行繁重的初始化操作,特别是如果仅在运行测试时需要初始化。

一般来说,执行测试的初始化应该在TestFixtureSetUp方法中完成,该方法每次执行fixture时只运行一次。但是,使用TestCaseSource属性生成测试用例时,这会更复杂。

由于必须执行TestCases才能创建测试,因此必须先创建对象实例才能创建测试。然后,当测试运行时,会创建另一个实例来运行它们。在你的问题中没有足够的信息来弄清楚为什么有两个“额外”调用到你的构造函数中,但是这可能是由于代码的某些其他方面,或者仅仅是你使用的NUnit的旧版本中的一个错误。你将不得不遍历这些构造函数调用,并检查堆栈跟踪以查看调用它们的内容。

您的m_GeometryProvider成员是否在TestCases方法以外的其他地方使用?如果不是,可以通过将其设置为在该方法中创建的临时字段来简化。然后,您可以通过使TestCases方法为静态来消除额外的构造函数调用。你说你不喜欢那个,但这是我们推荐的。事实上,在NUnit 3.0及更高版本中,它必须是静态的。

如果除了创建几何提供程序之外,还有其他初始化需要运行测试,那么应该使用TestFixtureSetUp方法。

+0

目前geometryProvider仅用于该方法,但随着更多测试的实施,我还需要从这些方法中访问它。不过非常感谢这个答案,它清楚了我已经假设的一些事情 - 特别是在3.x方法需要静态的事实。 – HimBromBeere

+0

我试图调试它,但对于这两个调用,我得到的同一个stacktrace只提到一个方法('JetBrains.ReSharper.UnitTestRunner.nUnit26.dll!JetBrains.ReSharper.UnitTestRunner.nUnit26.DelegatingTrunner.RunTests(...)' )。我添加了第二个方法,标记为名为'OtherTestCases'的'TestCaseSourceAttribute',该方法产生给被称为**三次**的构造函数。显然,引擎也会为每个'TestCaseSource'调用构造函数一次。 – HimBromBeere

+0

啊......你之前没有提到过Resharper。希望它没有区别。 是的,您的构造函数将被调用__each使用___包含在方法中的非静态TestCaseSource。一些版本的NUnit尝试缓存单个实例,但这是很久以前我不记得哪一个。 :-) – Charlie

相关问题