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

时间:2010-01-07 12:33:53

标签: unit-testing junit osgi

在运行JUnit测试时,有没有办法在私有方法中替换逻辑?

一些背景知识:我们有一些私有方法可以与OSGi容器中的bundle进行交互。这在单元测试中不可用,因此方法将失败。

我们已经查看了JMockIt但是方法替换功能似乎想要强制你替换类中相互调用的所有方法。

实施将是这样的:

public final doSomething() {  
    firstThing();
    secondThing();
}
private firstThing() {  
    // normal code
}
private secondThing() {  
    // code which is unavailable in a unit test
}

单元测试将指定secondThing()的新实现:

// replace secondThing() in impl with this secondThing()

private secondThing() {  
    // dummy code
}

// run tests

5 个答案:

答案 0 :(得分:6)

你当然可以用JMockit解决这个问题。 一种方法是定义“模拟”类,例如:

public class MyTest
{
    @Test
    public void testDoSomething()
    {
        new MockUp<ClassWhichDependsOnOtherBundles>()
        {
            @Mock
            void secondThing()
            {
               // do anything here
            }
        };

        new ClassWhichDependsOnOtherBundles().doSomething();
    }
}

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

答案 1 :(得分:3)

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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

  • 将其设为protected / public并在类似模拟的对象中覆盖它
  • 将该方法的功能移出一个helper类,该类是可注入的(通过依赖注入)。然后模拟那个帮助者将模拟注入到被测试的类中,而不是原始的heloper。

解决方法可能是一些字节码操作技术,但我不建议这样做。

答案 4 :(得分:-1)

有一个很好的存根模式

ProductionClass.java:


public class ProductionClass {
  ...
  //default visibility to make it available for stubbing
  void firstThing(){...}

  ...
}

BlaTest.java(与生产类相同的包):


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

一个不同的事情。我在示例代码中看到了一个final修饰符。注意使用最终修饰符。它们对于可测性是邪恶的。只有在真的有必要时才使用。