如何在java中测试本地内部类方法?
在许多应用程序中,我经常使用专用子算法(或简单定义良好的代码段)的算法。
到目前为止,当我编写主算法时,我为每个子算法创建了一个私有方法,如下例所示(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;
}
}
这工作得很好,但我不喜欢有大量的方法(subAlg01 和 subAlg02),即使是私有的,也仅由一种方法(mainAlg)使用。
最近我发现了本地内部类的使用,现在我的例子是(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;
}
}
我非常喜欢它,但现在我有以下问题:如何使用 JUnit 测试 subAlg01 和 subAlg02?
顺便说一句:我正在使用 Eclipse。
谢谢你的帮助。
编辑:我尝试更好地解释:我有一个排序算法,我想测试它以确保它按预期运行。这种排序算法仅由类 X 的方法 m 使用。我可以将其设为类 X 的私有方法,但类 X 通常与排序无关,那么为什么要使用排序方法“破坏”类 X 呢?所以我把它放在方法 m 中。一段时间后,我想改进我的排序算法(我让它更快),但我想确保它的行为符合预期,所以我想用原始测试重新测试它。
这就是我想做的,也许没有解决办法,我希望有人可以帮助我。
选择答案后进行编辑。我选择罗德尼的答案是因为他的解决方案是我采用的:一个独立的帮助器类帮助我(它是一个帮助器!)清楚地了解子方法是什么,并且它还使我能够测试它们。
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):
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).
Recently I dicovered the use of local inner classes and now my example is (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?
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.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您应该只测试类的公共接口,而不是私有成员或私有内部类。私有成员是实现细节,仅由类的公共方法(直接或间接)使用。因此,您可以通过它们的调用者方法间接对它们进行单元测试。如果您觉得这些单元测试没有足够的粒度,或者您无法感知您感兴趣的(某些)结果,这可能表明您的设计存在问题:类可能太大,尝试要做的事情太多,因此它的一些功能可能需要提取到一个单独的类中,然后可以直接在其中进行单元测试。
在当前的例子中,如果内部类本身包含很多代码,你可以简单地将它变成一个顶级类,然后你可以直接对其方法进行单元测试。
(顺便说一句,如果您的内部类不需要引用封闭的类实例,则它应该是static
。)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 bestatic
if it doesn't need to refer to the enclosing class instance.)Filippo,我理解您对这个问题和一些答案的沮丧。许多年前,当我第一次开始使用 JUnit 时,我也想测试私有代码,我认为专家们说这是一个坏主意,这是愚蠢的。
事实证明他们是对的(惊讶!),但只有在编写了相当多的测试之后我才明白为什么。您可能需要经历相同的过程,但您最终会得出相同的结论;-)
无论如何,在您的情况下,我会将
Nested
制作成一个适当的独立类,可能在一个单独的包中以表明它是一个辅助类。然后我会直接为其编写测试,独立于任何其他测试。然后我会为
NewStyle
编写测试,并仅关注NewStyle
的行为。(很可能我也会将
Nested
注入NewStyle
中,而不是在NewStyle
中实例化它 - 即使其成为NewStyle< 的参数 然后,当我在测试中编写
NewStyle
的测试时,我会传入
Nested
的实例并继续,如果我觉得特别棘手,我将从Nested
创建一个接口并创建第二个实现,并用它来测试NewStyle
。)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.
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
Nested
into 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.Then I'd write tests for
NewStyle
and focus only on the behaviour ofNewStyle
.(Quite probably I would also inject
Nested
intoNewStyle
rather than instantiating it withinNewStyle
-- i.e. make it an argument toNewStyle
's constructor.Then when I write tests for
NewStyle
in the test I'd pass in an instance ofNested
and carry on. If I felt particularly tricky, I'd create an interface out ofNested
and create a second implementation, and testNewStyle
with that, too.)您应该避免仅仅因为您而使代码过度复杂化
在您的情况下,您可以测试这些方法,如果它们是外部类的方法,或者如果您绝对需要内部类,则将其放置在 mainAlg() 方法之外,以便它在全局范围内可见。
然后可以使用 new NewStyle().new Nested().subAlg01(); 来调用它
You should avoid over complicating your code just because you
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.
this can then be called using
new NewStyle().new Nested().subAlg01();
您无法从外部访问这些类,因此 junit 无法测试它们。你必须公开一些东西来测试它们。
You cannot reach these classes from the outside, so junit cannot test Them. You must have things public to test Them.
嗯,我知道像 Groovy 这样的语言经常用于在 Java 上进行单元测试,并且能够透明地访问私有字段和方法......但我不确定嵌套类。我可以理解为什么你可能想做这种事情,但我对测试 getter 和 setter 采取同样的立场,应该将它们作为测试公共方法的副作用进行测试,如果它们不这样做以这种方式进行测试,那么他们为什么会在那里呢?
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?
当您的内部类的行为恰好是方法功能的核心部分时,问题就出现了:假设您有一个方法应该将可运行对象传递给第三个对象,而该对象恰好是一个实际上不应该的内部类一个单独的实体:在这种情况下,正确的单元测试几乎需要通过模拟第三个对象来练习所述内部类,并使用参数捕获来测试它应该做什么。
此类问题在对函数式编程有更多支持的语言中非常常见,其中测试传递给第三方的 lambda 几乎是必需的。
但是,正如前面所说,如果外部类从未使用过您的内部类,那么它只是一个实现细节,单独测试它是没有用的。
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.
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.
其实你可以测试一下你本地的内部类。但它需要实现一个接口。这样,您可以通过反射创建本地类的实例并将其转换为它的接口。一旦你有了接口类型,你就可以毫无问题地测试你的实现代码:
接口:
类:
测试:
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:
The class:
The test: