你应该用单独的单元测试来覆盖私有方法吗?

10 浏览
0 Comments

你应该用单独的单元测试来覆盖私有方法吗?

我习惯于在单元测试中使用一种方法,即为每个方法编写单独的单元测试。

通过将私有方法标记为 internal virtual(C#)并为其创建单独的单元测试来包括私有方法。最近,我在公司找不到一个支持这种方法的人 - 首选的方式是为公共方法编写单个单元测试,即使它包含对另一个私有方法的调用,在这种情况下,那些私有方法中的所有依赖关系也必须被模拟。我将在脑海中举一个简单的例子:

在上面的例子中,我的同事们说,正确的方法是为被调用的所有3个方法(SaveState、GetData、GetAnotherData)设置存根,这样单个单元测试将执行公共和私有方法并进行检查。

我习惯的做法是将方法声明为 internal virtual,这样该方法将对测试程序集可见,并首先为 DoSomeAdditionalWorkAsync 方法编写单独的测试,然后在编写 DoSomeWorkAsync 方法的另一个单元测试时使用部分模拟来模拟 DoSomeAdditionalWorkAsync 方法。

我听说过一个论点,即如果私有方法只在一个地方使用,并且为了代码的可读性而创建,则只有一个单元测试是可以接受的。但在这种情况下,下一个开发人员有可能重新使用带有断言的私有方法,而不知道它已经在一个单独的测试中被覆盖了。

答案是否取决于私有方法本身的复杂性?(私有方法越大,添加单元测试的理由就越多)

我在这里错了吗?我应该坚持我的同事们的建议吗?我试图搜索这个主题,但不确定应该搜索什么关键词。对于这种简单的情况,有什么最佳实践/建议吗?

提前感谢任何意见或建议。

0
0 Comments

问题的出现的原因:

1. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object.

2. If an object is hard to test via its public interface, it is going to be hard to use in the production code.

3. Test-driven development (TDD) requires the unit test to be the first client of the object, accessing only the class' public interface.

解决方法:

1. 不直接测试私有方法,而是测试调用私有方法的公共方法的效果。

2. 通过公共接口进行测试,如果对象在公共接口上测试困难,那么在实际生产代码中使用也会困难。

3. 在进行测试驱动开发时,将单元测试作为对象的第一个客户端,并且只访问其公共接口。

以下是整理后的

在进行单元测试时,我们应该如何处理私有方法呢?简短的回答是,我们不应该直接测试私有方法,而是只测试调用这些私有方法的公共方法对其产生的影响。单元测试是对象的客户端,就像代码中依赖该对象的其他类一样。事实上,如果我们正在实践测试驱动开发(TDD),那么单元测试会成为对象的第一个客户端。因此,单元测试应该只能访问类的公共接口。如果一个对象在其公共接口上测试困难,那么在实际生产代码中使用该对象也会变得困难。这就是单元测试暴露潜在设计问题的一个例子。

因此,解决这个问题的方法就是遵循上述原则。不直接测试私有方法,而是测试调用私有方法的公共方法的效果。通过公共接口进行测试可以更好地反映对象在实际使用中的行为。如果我们在公共接口上测试困难,那么我们需要重新审视对象的设计,以使其更易于使用和测试。这也是测试驱动开发的核心思想之一,即在编写实际代码之前先编写测试代码,并通过测试推动代码的设计和实现。

下面是一个示例,展示了如何测试一个类的公共方法,而不直接测试其私有方法:

public class MyClass {
    private int privateMethod(int a, int b) {
        return a + b;
    }
    public int publicMethod(int a, int b) {
        return privateMethod(a, b);
    }
}
public class MyClassTest {
    @Test
    public void testPublicMethod() {
        MyClass myClass = new MyClass();
        int result = myClass.publicMethod(2, 3);
        assertEquals(5, result);
    }
}

在上面的示例中,我们只测试了公共方法`publicMethod`,而没有直接测试私有方法`privateMethod`。通过测试公共方法,我们可以确保私有方法的正确性。这种方法可以更好地反映对象的行为,并且更易于维护和重构。

0
0 Comments

应该为私有方法编写单独的单元测试吗?

在软件开发中,我们经常需要编写单元测试来验证代码的正确性。通常情况下,我们会对类的公共接口进行测试,以确保输入和输出是正确的。这种做法的原因是,每个类和方法应该只负责一个单一的职责。

然而,在某些情况下,我们可能会遇到需要测试私有方法的情况。在一些大型的旧代码系统中,我们可能无法立即将所有代码重构为可测试状态。这时,一种常见的做法是将私有方法标记为受保护的虚方法,以便在测试中进行访问。但是,这种做法应该谨慎使用,不应滥用。

一般来说,如果你觉得一个私有方法足够复杂,需要编写单独的测试,那么你可能需要将其提取到一个独立的类中。如果私有方法并不复杂,那么编写单独的测试将导致过多地断言实现细节,使代码难以在未来进行重构。

此外,如果你需要为一个类设置许多模拟对象来进行测试,那么这可能是违反单一职责原则的表现。编写测试的一个非常好的副作用是,它揭示了任何设计不良的类。

总之,对于私有方法是否应该编写单独的单元测试,我们应该根据具体情况来决定。如果我们能够将代码重构为更可测试的状态,并通过公共接口进行测试,那么这将是更好的做法。而对于一些特殊情况,例如在大型旧代码系统中,我们可以使用标记为受保护的虚方法来进行测试。然而,我们应该避免滥用这种技术,并在可能的情况下将复杂的私有方法提取到独立的类中。

最后,我强烈推荐一本书给你,它是《单元测试的艺术》(The Art of Unit Testing)。这本书可以帮助你更好地理解单元测试的原则和技巧。

0