您是否认为将私有功能与类定义分开进行单元测试是正确的方法?

时间:2019-05-04 03:44:43

标签: unit-testing

当我编写一些打字稿代码时,我想对Foo Class的一些私有方法进行单元测试。

class Foo {
   private privateMethodWantToTest(argument) {
      return 'Bar'
   }
}

所以,我分离了这样的功能:


export function privateMethodWantToTest(this: Foo, argument) {
   return 'Bar'
}

class Foo {
   private privateMethodWantToTest(argument) {
      return privateMethodWantToTest.call(this, argument) 
   }
}

这种方法可能有效,但是有点多余。 并且导出所有功能可能不是一个好主意。

您如何看待这种方法? 有更好的单元测试解决方案,还是我不应该测试私有方法?

1 个答案:

答案 0 :(得分:1)

这取决于。首先,测试是关于发现(或防止)错误的方法。错误在实现细节中:不同的实现有不同的潜在错误。例如,考虑实现Fibonacci函数的不同方式:作为迭代/递归函数,闭式表达式(Moivre / Binet),查找表:接口始终相同,可能的错误差异很大。理解这一点的另一种方式是,在查看覆盖率时,您总是查看实现而不是接口。

但是,单元测试还有其他(次要)目标,即拥有一个健壮的测试套件,当实现细节发生变化时,它不会不必要地破坏。例如,如果私有函数的名称发生了变化,那么单元测试套件崩溃将是不幸的。因此,通常最好间接测试实现细节/私有功能(即通过调用公共接口来测试它们)。

但是,即使测试是针对公共API进行的,因此在内部结构发生更改时也不会中断,但内部结构的某些更改可能会使现有且仍在运行的测试无效:Fibonacci的Moivre / Binet实现测试将继续如果您切换到查找表,则可以正常工作。但是,查找表很可能需要其他测试方法。在这种情况下测试仍然可以工作的事实并不意味着不必维护测试套件。

如上所述,在测试中测试私有方法/函数具有缺点,因为它会使测试变得脆弱。但是,在某些情况下,从公共API测试这些功能不切实际。然后,最好的权衡仍然是分别测试私有功能(请记住:主要目标是发现错误,非脆弱测试套件是次要目标)。但是,您将必须找到使私有方法可用于测试的方法。如您所显示,一种可能性是将其公开,然后可以将其作为公共功能进行测试。

请注意,这不会降低测试套件的脆弱性:仅使一些实现细节可公开访问并不会改变其作为实现细节的性质。没有像“由公众代替私人,实现细节变得更加稳定”这样的魔术。严格来说,您出于测试目的(而不是其他人的访问)而使实现细节可访问。这将是一个体系结构约束,应该进行通信,例如,不要使用这些类/方法/函数。一种可能是,相应地命名它们。