如何在java中测试本地内部类方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3353318/
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-13 22:33:16  来源:igfitidea点击:

How do I test local inner class methods in java?

javaunit-testingjunitinner-classes

提问by Filippo Tabusso

In many application I often have algorithms which make use of dedicated sub-algorithms (or simply well defined pieces of code).

在许多应用程序中,我经常使用使用专用子算法(或简单定义良好的代码段)的算法。

Till now, when I wrote the main algorithm, i created a private method for each sub-algorithm like in the example below (OldStyle):

直到现在,当我编写主算法时,我为每个子算法创建了一个私有方法,如下例所示(OldStyle):

public class OldStyle {

    public int mainAlg() {
        int x = subAlg01();
        int y = subAlg02();
        int z = x * y;
        return z;
    }

    private int subAlg01() {
        return 3;
    }

    private int subAlg02() {
        return 5;
    }
}

This worked fine but I didn't like having a proliferation of methods (subAlg01 and subAlg02) which, even if private, were only used by one method (mainAlg).

这工作得很好,但我不喜欢有大量方法(subAlg01 和 subAlg02),即使是私有的,也只被一种方法(mainAlg)使用。

Recently I dicovered the use of local inner classes and now my example is (NewStyle):

最近我发现了本地内部类的使用,现在我的例子是(NewStyle):

public class NewStyle {

    public int mainAlg() {
        class Nested {

            public int subAlg01() {
                return 3;
            }

            public int subAlg02() {
                return 5;
            }
        }
        Nested n = new Nested();
        int x = n.subAlg01();
        int y = n.subAlg02();
        int z = x * y;
        return z;
    }
}

I like it very much but now I have the following problem: how do I test subAlg01 and subAlg02 using JUnit?

我非常喜欢它,但现在我遇到了以下问题:如何使用 JUnit 测试 subAlg01 和 subAlg02?

By the way: I'm using eclipse.

顺便说一句:我正在使用日食。

Thanks for you help.

谢谢你的帮助。

Edit: I try to explain better: I have, let's say, a sorting algorithm and I want to test it to be sure it runs as expected. This sorting algorithms is used by only method m of class X. I could make it a private method of class X but class X usually has nothing to do with sorting, so why "spoil" class X with the sorting method? So I put it inside method m. Some time later I want to improve my sorting algorithm (I make it faster) but I want to be sure that it's behavior is as expected, so I want to re-test it with the original tests.

编辑:我试着更好地解释:我有,比如说,一个排序算法,我想测试它以确保它按预期运行。这种排序算法只被 X 类的方法 m 使用。我可以让它成为 X 类的私有方法,但 X 类通常与排序无关,那么为什么用排序方法“破坏”X 类呢?所以我把它放在方法 m 中。一段时间后,我想改进我的排序算法(我让它更快),但我想确保它的行为符合预期,所以我想用原始测试重新测试它。

That's what I want to do, maybe there is no solution, I hope someone may help me.

这就是我想做的,也许没有解决方案,我希望有人可以帮助我。

Edit after answer choice. I selected Rodney answer because his solution is the one I adopted: a standalone helper class helps me (it's a helper!) to have a clear view of what are the sub methods and it also gives me the ability to test them.

选择答案后编辑。我选择 Rodney 的答案是因为他的解决方案是我采用的解决方案:一个独立的帮助程序类帮助我(它是一个帮助程序!)清楚地了解子方法是什么,它还使我能够测试它们。

采纳答案by Rodney Gitzel

Filippo, I understand your frustration with the problem and with some of the answers. When I first started using JUnit many years ago, I too wanted to test private code, and I thought it silly of the gurus to say it was a bad idea.

Filippo,我理解你对这个问题和一些答案的不满。多年前我第一次开始使用 JUnit 时,我也想测试私有代码,我认为专家们说这是一个坏主意是愚蠢的。

Turns out they were right (surprise!) but only after writing quite a few tests did I understand why. You might need to go through the same process, but you will eventually come to the same conclusion ;-)

结果证明他们是对的(惊讶!)但只有在写了很多测试之后我才明白为什么。您可能需要经历相同的过程,但最终会得出相同的结论 ;-)

Anyway, in your situation, I would make Nestedinto a proper standalone class, possibly in a separate package to make obvious that it's a helper classes. Then I would write tests for it directly, independent of any other tests.

无论如何,在你的情况下,我会制作Nested一个适当的独立类,可能在一个单独的包中,以明确它是一个帮助类。然后我会直接为它编写测试,独立于任何其他测试。

Then I'd write tests for NewStyleand focus only on the behaviour of NewStyle.

然后我会NewStyleNewStyle.

(Quite probably I would also inject Nestedinto NewStylerather than instantiating it within NewStyle-- i.e. make it an argument to NewStyle's constructor.

(大抵相当我也会注入NestedNewStyle而非内将其实例化NewStyle-即使它成为一个参数NewStyle的构造函数。

Then when I write tests for NewStylein the test I'd pass in an instance of Nestedand carry on. If I felt particularly tricky, I'd create an interface out of Nestedand create a second implementation, and test NewStylewith that, too.)

然后,当我NewStyle在测试中编写测试时,我会传入一个实例Nested并继续。如果我觉得特别棘手,我会创建一个接口Nested并创建第二个实现,并NewStyle用它进行测试。)

回答by Péter T?r?k

You should only test the public interface of classes, not private members or private inner classes. Private members are meant to be implementation details, used only by public methods of the class (directly or indirectly). So you can unit test these indirectly via their caller methods. If you feel you don't have enough granularity in those unit tests, or that you can't sense (some of) the results you are interested in, this probably signs a problem with your design: the class may be too big, trying to do too much, thus some of its functionality may need to be extracted into a separate class, where it can then be unit tested directly.

您应该只测试类的公共接口,而不是私有成员或私有内部类。私有成员意味着实现细节,仅由类的公共方法(直接或间接)使用。所以你可以通过它们的调用者方法间接地对它们进行单元测试。如果您觉得在这些单元测试中没有足够的粒度,或者您无法感知(某些)您感兴趣的结果,这可能表明您的设计存在问题:类可能太大,尝试做太多,因此它的一些功能可能需要提取到一个单独的类中,然后可以直接进行单元测试。

In the current example, if the inner class itself contains a lot of code, you may simply turn it into a top-level class, then you can unit test its methods directly.

在当前示例中,如果内部类本身包含大量代码,您可以简单地将其转换为顶级类,然后您可以直接对其方法进行单元测试。

(Btw your inner class should be staticif it doesn't need to refer to the enclosing class instance.)

(顺便说一句,您的内部类应该是,static如果它不需要引用封闭类实例。)

回答by Thorbj?rn Ravn Andersen

You cannot reach these classes from the outside, so junit cannot test Them. You must have things public to test Them.

您无法从外部访问这些类,因此 junit 无法测试它们。你必须有公共的东西来测试它们。

回答by Kingo

You should avoid over complicating your code just because you

你应该避免仅仅因为你

don't like having a proliferation of methods

不喜欢方法的泛滥

In your case you can test the methods if they are methods of the outer class or if you absolutely need the inner class then place it outside the mainAlg() method so it is visible globally.

在您的情况下,您可以测试这些方法,如果它们是外部类的方法,或者如果您绝对需要内部类,则将其放置在 mainAlg() 方法之外,以便它在全局范围内可见。

public class NewStyle {

    public int mainAlg() {

        Nested n = new Nested();
        int x = n.subAlg01();
        int y = n.subAlg02();

        int z = x * y;
        return z;
    }

    class Nested {

        public int subAlg01() {
            return 3;

        }

        public int subAlg02() {
            return 5;
        }
    }
}

this can then be called using new NewStyle().new Nested().subAlg01();

然后可以使用 new NewStyle().new Nested().subAlg01();

回答by mezmo

Hm, I know that languages like Groovy are often used to do unit testing on Java, and are able to access private fields and methods transparently.....but I'm not sure about nested classes. I can understand why you might want to do this sort of thing, but I kind of take the same position I take with testing getters and setters, they should be tested as a side effect of testing your public methods, and if they don't get tested that way, then why are they there to begin with?

嗯,我知道像 Groovy 这样的语言经常用于在 Java 上进行单元测试,并且能够透明地访问私有字段和方法......但我不确定嵌套类。我可以理解为什么你可能想要做这种事情,但我采取与测试 getter 和 setter 相同的立场,他们应该作为测试公共方法的副作用进行测试,如果他们不这样做以这种方式进行测试,那么他们为什么要开始呢?

回答by bob

The issue comes when your inner class's behavior happens to be a core part of what a method does: Say that you have a method is supposed to pass a runnable to a third object, which happens to be an inner class that really shouldn't be a separate entity: In this case, proper unit testing pretty much requires exercising said inner class by mocking that third object, and using argument capture to test it does what it should.

当您的内部类的行为恰好是方法功能的核心部分时,问题就出现了:假设您有一个方法应该将可运行对象传递给第三个对象,而这恰好是一个真正不应该是的内部类一个单独的实体:在这种情况下,正确的单元测试几乎需要通过模拟第三个对象来练习所述内部类,并使用参数捕获来测试它应该做什么。

This kinds of issues are very common in languages that have more support for functional programming, where testing lambdas passed to third parties is pretty much a requirement.

这种问题在对函数式编程有更多支持的语言中很常见,在这种情况下,测试传递给第三方的 lambdas 几乎是必需的。

But, as it was said before, if your inner class is never used by an outside party, then it's just an implementation detail, and testing it separately is just not useful.

但是,正如之前所说,如果您的内部类从未被外部方使用过,那么它只是一个实现细节,单独测试它是没有用的。

回答by Kai Sternad

Actually, you can test your local inner class. But it needs to implement an interface. This way you can create an instance of the local class via reflection and cast it to it's interface. Once you have the interface type, you can test your implementing code without problems:

实际上,您可以测试本地内部类。但是它需要实现一个接口。通过这种方式,您可以通过反射创建本地类的实例并将其转换为它的接口。一旦你有了接口类型,你就可以毫无问题地测试你的实现代码:

The interface:

界面:

public interface Algorithm {
    int subAlg01();
    int subAlg02();
}

The class:

班上:

public class NewStyle {
    public int mainAlg() {
        class Nested implements Algorithm {

            public int subAlg01() {
                return 3;
            }

            public int subAlg02() {
                return 5;
            }
        }
        Nested n = new Nested();
        int x = n.subAlg01();
        int y = n.subAlg02();
        int z = x * y;
        return z;
    }
}

The test:

考试:

public class NewStyleTest {

    @Test
    public void testLocal() throws ClassNotFoundException,
            NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        Class<?> forName = Class.forName("NewStyleNested");
        Constructor<?> declaredConstructor = forName
                .getDeclaredConstructor(NewStyle.class);
        declaredConstructor.setAccessible(true);
        Algorithm algorithm = (Algorithm) declaredConstructor
                .newInstance(new NewStyle());

        assertEquals(algorithm.subAlg01(), 3);
        assertEquals(algorithm.subAlg02(), 5);
    }
}