junit 和 java:测试非公共方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/440786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:39:23  来源:igfitidea点击:

junit & java : testing non-public methods

javaunit-testingtestingjunit

提问by jbu

JUnit will only test those methods in my class that are public. How do I do junit testing on the ones that are not (i.e., private, protected)?

JUnit 只会测试我的类中的那些公共方法。我如何对那些不是(即私有的、受保护的)的进行 junit 测试?

I can test them by not using junit, but I was wondering what the junit standard method was.

我可以不使用 junit 来测试它们,但我想知道 junit 标准方法是什么。

回答by Paul Tomblin

Look for "PrivateAccessor.invoke". My code imports it from "junitx.util", but I don't know where it came from.

寻找“PrivateAccessor.invoke”。我的代码从“junitx.util”导入它,但我不知道它来自哪里。

回答by starblue

The simplest solution is to put the JUnit tests in the same package (but different directory) and use default (i.e. package-private) visibility for the methods.

最简单的解决方案是将 JUnit 测试放在同一个包(但不同的目录)中,并对方法使用默认(即包私有)可见性。

Another more complicated approach is to use reflection to access private methods.

另一种更复杂的方法是使用反射来访问私有方法。

回答by MattK

One school of thought about unit testing says that you should only be able to test public methods, because you should only be unit-testing your public API, and that by doing so, you should be covering the code in your non-public methods. Your mileage may vary; I find that this is sometimes the case and sometimes not.

一种关于单元测试的流派认为你应该只能测试公共方法,因为你应该只对公共 API 进行单元测试,并且通过这样做,你应该覆盖非公共方法中的代码。你的旅费可能会改变; 我发现有时是这样,有时则不是。

With that said, there are a couple of ways to test non-public methods:

话虽如此,有几种方法可以测试非公共方法:

  • You can test protected and package-scope methods by putting your unit tests in the same package as the classes they're testing. This is a fairly common practice.
  • You can test protected methods from unit tests in another package by creating a subclass of the class under test that overrides the methods you want to test as public, and having those overridden methods call the original methods with the super keyword. Typically, this "testing subclass" would be an inner class in the JUnit TestCase class doing the testing. This is a little bit more hacky, in my opinion, but I've done it.
  • 您可以通过将单元测试与它们正在测试的类放在同一个包中来测试受保护和包范围的方法。这是一种相当普遍的做法。
  • 您可以通过创建被测类的子类来测试另一个包中单元测试中受保护的方法,该子类将您要测试为公共的方法覆盖,并让这些覆盖的方法使用 super 关键字调用原始方法。通常,这个“测试子类”将是执行测试的 JUnit TestCase 类中的一个内部类。在我看来,这有点棘手,但我已经做到了。

Hope this helps.

希望这可以帮助。

回答by Kent Beck

As with many unit testing problems, testing private methods is actually a design problem in disguise. Rather than try to do anything tricky to test private methods, when I find myself wishing to write tests for private methods I take a minute to ask myself, "How would I need to design this so I could test it thoroughly through public methods?"

与许多单元测试问题一样,测试私有方法实际上是变相的设计问题。与其尝试做任何棘手的事情来测试私有方法,当我发现自己希望为私有方法编写测试时,我花一点时间问自己,“我需要如何设计它,以便我可以通过公共方法对其进行彻底测试?”

If that doesn't work, JUnitX allows testing private methods, although I believe it is only available for JUnit 3.8.

如果这不起作用,JUnitX 允许测试私有方法,尽管我相信它仅适用于 JUnit 3.8。

回答by marcumka

If you have a significant amount of logic buried under relatively few "Public" entry points, you are probably violating the Single Responsibility Principle. If possible, you'll want to refactor the code into multiple classes, ultimately leading to more "Public" methods from which to test.

如果您在相对较少的“公共”入口点下隐藏了大量逻辑,则您可能违反了单一职责原则。如果可能,您将希望将代码重构为多个类,最终会产生更多可供测试的“公共”方法。

回答by cletus

I nearly always use Spring in my Java projects and, as such, my objects are built for dependency injection. They tend to be fairly granular implementations of public interfaces that are assembled within the application context. As such, I rarely (if ever) have the need to test private methods because the class itself is small enough that it simply isn't an issue.

我几乎总是在我的 Java 项目中使用 Spring,因此,我的对象是为依赖注入而构建的。它们往往是在应用程序上下文中组装的公共接口的相当精细的实现。因此,我很少(如果有的话)需要测试私有方法,因为类本身足够小,它根本不是问题。

Even when I don't use Spring I tend to adopt the same practices of assembling small and simple objects into larger and larger abstractions, each of which is relatively simple but made complex by the aggregated objects.

即使当我不使用 Spring 时,我也倾向于采用相同的做法,将小而简单的对象组装成越来越大的抽象,每个抽象都相对简单,但通过聚合对象变得复杂。

In my experience, having the need to unit test private methods is an indicator that what you're teesting could (and should) be simplified.

根据我的经验,需要对私有方法进行单元测试表明您正在测试的内容可以(并且应该)被简化。

That being, if you still really feel the need:

也就是说,如果你仍然觉得有必要:

  • Protected methods can be tested by subclasses;
  • Package private methods can be tested by putting the unit tests in the same package; and
  • Private methods can be unit tested by providing, for example, a package private factory proxy method. Not ideal but private does mean private.
  • 受保护的方法可以通过子类进行测试;
  • 可以通过将单元测试放在同一个包中来测试包私有方法;和
  • 私有方法可以通过提供例如包私有工厂代理方法来进行单元测试。不理想,但私人确实意味着私人。

回答by Spoike

You usually don't test private methods because they can only (normally) be tested indirectly through another public method. When you're test driving and make private methods then they are usually a result of an "extract method" refactoring and are already by then tested indirectly.

您通常不测试私有方法,因为它们只能(通常)通过另一个公共方法间接测试。当您测试驱动并创建私有方法时,它们通常是“提取方法”重构的结果,并且已经被间接测试。

If you are concerned about testing a private method with lots of logic then the smartest thing you could do is to move that code into another class in a public method. Once you've done that, the previous method that used this code can have it's testing simplified by having the functionality provided by a stub or a mock.

如果您担心测试具有大量逻辑的私有方法,那么您可以做的最明智的事情是将该代码移动到公共方法中的另一个类中。完成此操作后,使用此代码的先前方法可以通过存根或模拟提供的功能来简化测试。

回答by duffymo

When you write a JUnit test, you have to do a subtle mind shift: "I'm a client of my own class now." That means private is private, and you only test the behavior that the client sees.

当您编写 JUnit 测试时,您必须进行微妙的思想转变:“我现在是自己班级的客户。” 这意味着私有是私有的,您只测试客户端看到的行为。

If the method really should be private, I'd consider it a design flaw to make it visible just for the sake of testing. You've got to be able to infer its correct operation based on what the client sees.

如果该方法真的应该是私有的,我会认为它是一个设计缺陷,只是为了测试而使其可见。您必须能够根据客户看到的内容推断其正确操作。

In the three years that have passed since I originally wrote this, I've started approaching the problem slightly differently, using Java reflection.

自从我最初写这篇文章以来已经过去了三年,我开始以稍微不同的方式处理这个问题,使用 Java 反射。

The dirty little secret is that you can test private methods in JUnit just as you would public ones, using reflection. You can test to your heart's content and still not expose them as public to clients.

肮脏的小秘密是,您可以使用反射测试 JUnit 中的私有方法,就像测试公共方法一样。您可以根据自己的意愿进行测试,但仍然不会将它们公开给客户。

回答by Bill K

In agreement with just about every post--you should probably refactor and probably not test private except through public, just wanted to add a different way to think about it...

几乎同意每个帖子-您可能应该重构并且可能除了通过公共之外不测试私有,只是想添加一种不同的思考方式......

Think of your class itself as a "Unit", not a method. You are testing the class and that it can maintain a valid state regardless of how it's public methods are called.

将您的类本身视为一个“单元”,而不是一个方法。您正在测试该类,无论其公共方法如何调用,它都可以保持有效状态。

Calling private methods can destroy the encapsulation and actually invalidate the tests.

调用私有方法会破坏封装并使测试实际上无效。

回答by Steve B.

I've come across the same issue, and the "if it needs to be private it probably should be refactored" doesn't sit right with me.

我遇到了同样的问题,“如果它需要私有,它可能应该重构”并不适合我。

Suppose you have sort of functionality that you want to separate out in some way internal to the class. For example, suppose I have something like this:

假设您希望以某种方式在类内部分离出某种功能。例如,假设我有这样的事情:

public class HolderOfSomeStrings{

    private List<String> internal_values;

    public List<String> get()
    {
       List<String> out = new ArrayList<String>();
       for (String s:internal_values)
       { 
           out.add(process(s));
       }
      return get;
    }

   private static String process(String input)
   {
     //do something complicated here that other classes shouldn't be interested in
    }

}

The point here is that junit forces me to make process public, or at least protected, or to put it in it's own utility class. But if it's some sort of internal logic of HolderOfSomeStrings, it's not at all clear to me that this is correct—it seems to me that this ought to be private, and making it more visible gums up the code in some way.

这里的重点是 junit 强迫我将进程公开,或者至少是受保护的,或者将它放在它自己的实用程序类中。但是,如果它是 HolderOfSomeStrings 的某种内部逻辑,我就完全不清楚这是否正确——在我看来,这应该是私有的,并且在某种程度上使其更加可见会破坏代码。