Java Unit Test: Replace a private method under test
在运行JUnit测试时,有没有办法在私有方法中替换逻辑?
一些背景知识:我们有一些私有方法可以与OSGi容器中的bundle进行交互。 这在单元测试中不可用,因此方法将失败。
我们已经看过JMockIt但是方法替换功能似乎想要强制你替换类中相互调用的所有方法。
实现将是这样的:
1 2 3 4 5 6 7 8 9 10 | public final doSomething() { firstThing(); secondThing(); } private firstThing() { // normal code } private secondThing() { // code which is unavailable in a unit test } |
单元测试将指定secondThing()的新实现:
1 2 3 4 5 6 7 | // replace secondThing() in impl with this secondThing() private secondThing() { // dummy code } // run tests |
你当然可以用JMockit来解决这个问题。
一种方法是定义"模拟"类,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class MyTest { @Test public void testDoSomething() { new MockUp<ClassWhichDependsOnOtherBundles>() { @Mock void secondThing() { // do anything here } }; new ClassWhichDependsOnOtherBundles().doSomething(); } } |
只有模拟类中的
也可以使用JMockit Expectations API,部分模拟。
您将实现与osgi对象的创建耦合(在secondThing()或类本身内部执行)。如果您从外部将实现传递到您的类中,则可以在测试时使用存根/模拟。
我也认为依赖注入会解决这个问题。
如果您不希望项目中有另一个框架,并且这是唯一一个出现问题的地方,您可以为secondThing定义一个接口,并为其创建2个实现,一个用于原始代码,另一个用于unittest。
我的建议 - 重新设计你的应用程序。如果要更改
-
使它
protected /public 并在类似于模拟的对象中覆盖它 - 将函数从方法中移出到一个可注入的辅助类中(通过依赖注入)。然后模拟那个帮助者将模拟注入到被测试的类中,而不是原始的heloper。
解决方法可能是一些字节码操作技术,但我不建议这样做。
有一个很好的存根模式
ProductionClass.java:
1 2 3 4 5 6 7 8 9 | <wyn> public class ProductionClass { ... //default visibility to make it available for stubbing void firstThing(){...} ... } </wyn> |
BlaTest.java(与生产类相同的包):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <wyn> public class BlaTest { @Test void test_xx(){ //use stubbed impl ProductionClass sut = new ProductionClassStubbed(); sut.doSomething(); } } class ProductionClassStubbed extends ProductionClass{ @Override void firstThing(){ //stub out fill in what you want (like dummy behaviour) } } </wyn> |
一个不同的事情。我在示例代码中看到了一个final修饰符。注意使用final修饰符。它们对于可测性是邪恶的。只有在真的有必要时使用。