我想测试一个私有方法 - 我的设计有问题吗?

发布于 2024-12-28 22:45:36 字数 439 浏览 2 评论 0原文

因此,我对软件测试非常陌生,并且正在考虑向我的一个应用程序添加一些测试。我有一个公共方法 addKeywords() ,它一路上调用一个私有方法removeInvalidOperations()。这个私有方法调用外部 API,大约有 50 行代码。由于我认为这是一个有点复杂的方法,因此我想测试它,而不必通过调用 addKeyword() 方法来进行测试。但这似乎不可能(至少通过 JUnit 不可能)。

我查看的信息表明,测试私有方法的愿望可能是一种代码味道。有人建议这可能是一个迹象,表明应该将其重构为一个单独的类并公开。此外,还有一些建议,如果您确实需要,则可以编辑生产代码,例如更改私有方法的可见性。

我真的不明白为什么我当前的代码设计有问题,但也不喜欢编辑生产代码以满足我的测试需求的想法。

正如我所说 - 我对测试相当陌生,因此非常感谢任何帮助。另外,如果我可以提供任何进一步的信息来帮助解答,请告诉我。

So I'm extremely new to software testing, and am looking at adding a couple of tests to one of my applications. I have a public method addKeywords() which along the way calls a private method removeInvalidOperations(). This private method makes calls to an external API and is ~50 lines of code. As I consider this to be a somewhat complex method I would like to test this without having to do so through calling the addKeyword() method. Yet this does not seem to be possible (at least not though JUnit).

The information I have looked at is suggesting that the desire to test ones private methods could be a code smell. Some people suggest that it may be a sign that this should be refactored into a separate class and made public. Also, there are the suggestions that if you really need to then you can make edits to your production code e.g. change the visibility of the private method.

I don't really see why I have a problem with my current code design, but also don't like the idea of editing my production code to suit my tests needs.

As I say - I'm rather new to testing, so any help is much appreciated. Also, please let me know if there is any further info I can provide to help with the answers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

柳絮泡泡 2025-01-04 22:45:36

我建议重构它。

我查看的信息表明测试的愿望
私有方法可能有代码味道。有些人建议
这可能表明这应该被重构为一个单独的类
并公开。

您在自己的问题中已经阐述了支持和反对的各种理由,您似乎很清楚这些论点。但你有一个看起来相当复杂并且涉及外部 API 的方法。 这值得自己测试。 removeInvalidOperations() 仍然可以是其所在类的私有方法,但它基本上会委托给另一个依赖项。

class YourClass
{
    private OperationRemover remover;

    public void addKeywords() {
        // whatever
        removeInvalidOperations();
    }

    private void removeInvalidOperations() {
         remover.remove();
    }
}

这为您带来了额外的好处,即能够在某个时刻替换此依赖项,包括能够测试您的 addKeywords() 方法,而无需实际进行外部 API 调用,这将使测试该方法变得更加容易。例如,OperationRemover 可以是一个接口,出于测试目的,您只需传入一个存根代替其位置,而不是生产中使用的具体版本。至于您的具体版本,您可以独立于现有类发生的情况为其编写测试。

我真的不明白为什么我当前的代码设计有问题,
但也不喜欢编辑我的生产代码以适合我的想法
测试需求。

更容易的可测试性是一个附带好处。从另一个角度来看:您实际上所做的是使代码松散耦合且可扩展。上面,我们将对外部 API 的调用与可能需要使用结果的代码分开。外部 API 可能会发生变化。您可能从一项服务转到另一项服务,但使用结果的代码不必关心。该类可以保持不变,只有实际发出调用的类需要修改(或替换)。

现实世界的示例:2007 年,您在美国大型金融中心的一家银行工作。您的应用程序需要使用帐户信息。您的代码会访问银行内部的某种 Web 服务,并以所需的形式获取所需的信息,然后继续进行处理。 2008 年,美国金融业崩溃,您的银行(濒临崩溃)被另一家银行吞并。您的应用程序不会受到影响,但现在您必须访问幸存银行中已存在的另一个 API 才能从那里获取帐户信息。使用此帐户信息的代码是否需要更改?未必。它与以前的帐户信息相同,只是来源不同。不,需要改变的只是调用 API 的实现。使用代码永远不必知道。

事实上,这种松散耦合还促进和方便了测试,这是一个好处。

I suggest refactoring it.

The information I have looked at is suggesting that the desire to test
ones private methods could be a code smell. Some people suggest that
it may be a sign that this should be refactored into a separate class
and made public.

You have covered the various reasons for and against it in your own question, you seem to be well aware of the arguments. But you have a method that seems rather complicated and involves an external API. That is worth testing on its own. removeInvalidOperations() can still be a private method on the class it is in, but it would basically delegate to another dependency.

class YourClass
{
    private OperationRemover remover;

    public void addKeywords() {
        // whatever
        removeInvalidOperations();
    }

    private void removeInvalidOperations() {
         remover.remove();
    }
}

This gives you the added benefit of being able to replace this dependency at some point, including being able to test your addKeywords() method without actually placing an external API call, which would make testing that method easier. OperationRemover could be an interface, for example, and for testing purposes, you simply pass in a stub in its place instead of the concrete version used in production. As for your concrete version, you can write tests for it independently of what is happening with your existing class.

I don't really see why I have a problem with my current code design,
but also don't like the idea of editing my production code to suit my
tests needs.

Easier testability is a side-benefit. Look at it another way: What you are actually doing is making the code loosely coupled and extensible. Above, we have separated the call to the external API from the code that might need to use the result. The external API could change. You might go from one service to another, but the code that uses the result does not have to care. That class can stay the same, only the class that actually places the calls needs to be modified (or replaced).

Real world example: The year is 2007 and you work for a bank in a large financial center in the United States. Your application needs to use account information. Your code reaches out to a web service of some sort inside the bank and gets the information it needs, in the shape it needs, then goes on about its processing. In 2008, the US financial sector implodes, and your bank (which is on the verge of collapse) is gobbled up by another bank. Your application is spared, except now you have to reach out to a different API that already exists within the surviving bank to get account information from there. Should the code that consumes this account information need to change? Not necessarily. It's the same account information as before, just from a different source. No, all that needs to change is the implementation invoking the APIs. Consuming code never has to know.

The fact that such loose coupling also promotes and facilitates testing is a bonus.

鯉魚旗 2025-01-04 22:45:36

如果它是私有,则不能将其视为应用程序 API 的一部分,因此测试它确实是一种代码味道 - 当测试失败时,这样可以吗?

单元测试应该是面向功能,而不是面向代码。您测试功能单元,而不是代码单元。

无论理念如何,实现之外的类在不侵入 JVM 的情况下都无法访问私有方法,因此您运气不好 - 您要么必须更改方法的可见性,要么将受保护的测试 API 设置为单元测试类扩展,或通过调用使用该函数的公共方法来间接测试该函数。

If it's private, it can't be considered part of your application's API, so testing it is indeed a code smell - when the test breaks, is that OK or not?

Unit tests are supposed to be functionality oriented, not code oriented. You test units of functionality, not units of code.

Regardless of philosophy, a class outside of your implementation cannot access the private method without hacking the JVM, so you're out of luck - you either have to change the method's visibility, make a protected testing API the unit-test class extends, or test the function indirectly by calling the public methods making use of it.

要走就滚别墨迹 2025-01-04 22:45:36

通常您不想测试私有方法,但也有例外。

如果出现以下情况,您可能会想要测试私有方法:

  1. 您没有仔细考虑如何测试私有方法
    通过调用现有的公共方法间接实现。

  2. 你的类的 API 太不灵活了。公共方法需要更多
    参数,或者一些私有方法需要公开。

  3. 你的类的 API 足够灵活,但在公共之下
    方法 它有一些非常复杂的私有方法

根据您的问题,您可能属于上述任何一种情况。

对于(1),显然你应该首先尝试找到一种方法来使用现有的公共方法来测试你的私有方法。

对于(2)和(3),单元测试不会告诉您属于哪种情况。您需要做的是编写一些示例代码。作为Josh Bloch 建议,为您的 API 编写一些用例。您的 API 应该是满足您的用例所需的最小公共方法集。

(3) 是可以测试私有方法的情况。有各种技巧。对于生产代码,这些比将您的方法暴露给 API 用户(使其公开)更好,以便您可以测试它。或者将相关功能分成 2 个类,以便您可以测试它。

您可以根据信息来思考,而不是用“代码味道”来思考,这是不精确和主观的隐藏。可能会更改的设计决策不应在公共 API 中公开。最好,可能改变的设计决策也不应该暴露在单元测试中——这就是人们建议不要测试私有方法的原因。

但是,如果您确实认为对私有方法进行单元测试很重要,并且如果您无法通过公共方法充分做到这一点,那么请不要牺牲代码的正确性!测试私有方法。最糟糕的情况是您的测试代码更加混乱,并且当私有方法更改时您必须重写测试。

Usually you wouldn't want to test a private method, but there are exceptions.

You might be tempted to test a private method if:

  1. You haven't thought carefully about how to test the private method
    indirectly by calling the existing public methods.

  2. Your class's API is too inflexible. The public methods need more
    parameters, or some of the private methods need to be made public.

  3. Your class's API is flexible enough, but underneath the public
    methods it has some pretty complicated private methods going on
    underneath.

Based on your question, you could be in any of those cases.

For (1), obviously you should first try to find a way to test your private method with the existing public methods.

For (2) and (3), unit tests won't tell you which case you're in. What you need to do is write some example code. As Josh Bloch recommends, code some use cases for your API. Your API should be the minimal set of public methods required to satisfy your use cases.

(3) is the case where it's OK to test private methods. There are various tricks for that. For production code, these are better than exposing your method to the API user (making it public) just so you can test it. Or splitting related functionality into 2 classes just so you can test it.

Instead of thinking in terms of "code smells", which is imprecise and subjective, you can think in terms of information hiding. Design decisions that are likely to change should not be exposed in your public API. Preferably, design decisions that are likely to change should not be exposed to your unit tests either -- that's why people recommend against testing private methods.

But if you really think it's important to unit-test your private method, and if you can't do it adequately via the public methods, then don't sacrifice the correctness of your code! Test the private method. Worst case is your test code is messier, and you have to rewrite the tests when the private method changes.

温柔女人霸气范 2025-01-04 22:45:36

如果您不想调用 addKeywords(),也许您应该添加另一个公共方法 testRemoveInvalidOperations(),它只调用私有 removeInvalidOperations()< /代码>。您可以稍后删除该测试。

If you don't want to call addKeywords(), perhaps you should just add another public method testRemoveInvalidOperations(), which just calls the private removeInvalidOperations(). You can remove the test at a later date.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文