关于junit:Java单元测试:替换测试中的私有方法

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();
    }
}

只有模拟类中的secondThing()方法才会被JMockit替换。
也可以使用JMockit Expectations API,部分模拟。


您将实现与osgi对象的创建耦合(在secondThing()或类本身内部执行)。如果您从外部将实现传递到您的类中,则可以在测试时使用存根/模拟。


我也认为依赖注入会解决这个问题。
如果您不希望项目中有另一个框架,并且这是唯一一个出现问题的地方,您可以为secondThing定义一个接口,并为其创建2个实现,一个用于原始代码,另一个用于unittest。


我的建议 - 重新设计你的应用程序。如果要更改private方法的行为:

  • 使它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修饰符。它们对于可测性是邪恶的。只有在真的有必要时使用。