1

我在 C# 和 rhino mocks 方面都很新。我搜索并找到了与我的问题类似的主题,但找不到合适的解决方案。

我试图了解在我的单元测试中是否调用了私有方法。我正在使用 rhino mock,阅读了很多关于它的文件,其中一些只是说将方法的访问说明符从私有更改为公共,但我无法更改源代码。我试图将源文件链接到我的测试项目,但它没有改变。

  public void calculateItems()
    {
        var result = new Result(fileName, ip, localPath, remotePath);

        calculateItems(result, nameOfString);
    }

    private void calculateItems(Result result, string nameOfString )

从上面的代码可以看出,我有两个方法名称完全相同,calculateItems,但是公共的一个没有参数,私有的一个有两个参数。我想了解当我在单元测试中调用公共方法时,是否调用了私有方法?

    private CalculateClass sut;
    private Result result; 

    [SetUp]
    public void Setup()
    {
      result = MockRepository.GenerateStub<Result>();
      sut = new CalculateClass();
    }

    [TearDown]
    public void TearDown()
    {

    }

    [Test]
    public void test()
    {     
        sut.Stub(stub => stub.calculateItems(Arg<Result>.Is.Anything, Arg<string>.Is.Anything));

        sut.calculateItems();

        sut.AssertWasCalled(stub => stub.calculateItems(Arg<Result>.Is.Anything, Arg<string>.Is.Anything));
    }

在我的单元测试中,我遇到了这样一个错误,上面写着“calculateItems 的重载方法没有两个参数”。有没有办法在不更改源代码的情况下对其进行测试?

4

3 回答 3

5

你在测试错误的东西。私有方法是私有的。它们与使用代码无关,单元测试与其他代码一样使用代码。

在您的测试中,您测试和验证组件的外向功能。它的内部实现细节与测试无关。所有测试关心的是调用的操作是否产生预期的结果。

所以你必须问自己的问题是......调用此操作时的预期结果是什么?:

calculateItems()

它不返回任何东西,那么做了什么?它以某种方式修改了什么状态? 就是您的测试需要观察的,不是实现细节,而是可观察的结果。(如果操作没有可观察到的结果,那么“通过”或“失败”之间没有区别,所以没有什么要测试的。)

我们看不到您的代码的详细信息,但可观察到的结果可能完全耦合到另一个组件。如果是这种情况,那么其他组件是此操作的依赖项,并且单元测试的目标是模拟该依赖项,以便可以独立于依赖项来测试操作。然后可能需要修改组件,以便提供依赖关系而不是内部控制。(这被称为依赖倒置原则。)


还要注意...

但我无法更改源代码

这完全是一个单独的问题。如果您真的无法更改源代码,那么这些测试的价值就会大大降低,甚至可能完全消除。如果测试失败,你能做些什么呢?没有。因为您无法更改代码。那你在测试什么?

请记住,程序员编写无法进行有意义的单元测试的代码不仅可能而且不幸的是非常普遍。如果此代码是由其他人提供给您的,并且由于某些非技术原因您被禁止更改它,那么其他人将有责任更正代码。“更正”可能包括“使有意义的单元测试成为可能”。(或者,老实说,他们应该对它进行单元测试。不是你。)

于 2019-03-01T13:57:26.167 回答
0

如果您的公共方法调用您的私有方法,那么您的测试中也会发生同样的事情。测试只不过是可以运行和调试的代码,您可以尝试一下,看看会发生什么。

私有方法不能直接测试,但可以通过他们的公共调用者进行测试,这就是你正在做的,所以一切都很好。拥有这样的设置是否是一个好主意,这完全是一个不同的故事,但我现在不打算这样做。

现在,让我们讨论一下您实际测试的内容。

单元测试不应该对他们测试的代码有深入的了解。原因是你应该有输入和输出,你不应该关心两者之间发生了什么。

如果您重构代码并消除私有方法,那么即使您对公共方法的输入和输出保持不变,您的测试也会中断。这不是一个好位置,这就是我们所说的脆性测试。

所以围绕公共方法添加你的功能测试,验证你得到你期望的帽子,不要担心它是否调用你的私有方法。

于 2019-03-01T14:02:27.487 回答
0

当你说你需要知道你的私有方法是否被调用时,这可以有两种不同的解释:

  1. 您希望确保在一个特定测试中调用私有方法,使其成为该测试的成功标准。

  2. 您想知道您的任何测试用例是否调用了私有方法。您可能对此感兴趣,因为您想确定私有方法是否包含在您的测试套件中,或者如您所说,只是为了了解代码中实际发生的情况。

关于第二种解释:如果您想了解代码中发生了什么,一个好的方法是使用调试器并单步执行代码以查看调用了什么函数。由于我不是 C# 专家,我不能推荐任何特定的调试工具,但在网上找到一些关于此的建议应该不难。这种方法将满足您的要求,不需要更改源代码

另一种可能性,特别是如果您对测试是否覆盖您的私有函数感兴趣,是使用 C# 的测试覆盖工具。覆盖工具会告诉你是否调用了私有方法。同样,这不需要对源代码进行任何更改。

关于您的问题的第一种解释:如果您想测试某个 privat 函数是否被称为测试成功标准的一部分,您最好使用使用公共 API 的测试来执行此操作。那么,在这些测试中,你应该可以判断是否调用了私有函数,因为私有函数对测试结果的影响。

而且,与其他意见相反,您应该测试实现。单元测试的主要目标是找出代码中的错误。不同的实现有不同的错误。这就是为什么人们还使用覆盖工具来查看他们是否已经覆盖了他们的实现代码。而且,覆盖范围还不够,您还需要检查表达式的边界情况等。当然,拥有可维护的测试和在重构的情况下不会不必要地中断的测试是好的目标(为什么通过公共 API 进行测试通常是一种好方法 -但并非总是如此),但与查找所有错误的目标相比,它们是次要目标。

于 2019-03-01T20:43:47.683 回答