使用JMockit模拟自动连接的接口实现

时间:2009-12-30 15:02:30

标签: java spring junit mocking jmockit

我们正在为一个使用Spring自动装配注入依赖关系的类编写JUnit测试,该依赖关系是一个接口的实例。由于被测试的类从未显式实例化依赖项或者它是否在构造函数中传递,因此看起来JMockit也没有义务实例化它。

到目前为止,我们一直在使用SpringRunner为我们提供Spring加载模拟依赖项,这是有效的。我们不喜欢的两件事是:1)每次运行测试时都必须加载和初始化Spring框架,这不是非常快速的; 2)我们被迫显式创建所有模拟依赖项作为真正的类, JMockit有助于消除。

以下是我们测试内容的简化示例:

public class UnitUnderTest {

   @Autowired
   ISomeInterface someInterface;

   public void callInterfaceMethod() {

      System.out.println( "UnitUnderTest.callInterfaceMethod calling someInterface.doSomething");
      someInterface.doSomething();
   }

}

所以,问题是,有没有办法让JMockit创建一个模拟someInterface

5 个答案:

答案 0 :(得分:12)

JMockit将始终实例化一个模拟接口(最终模拟字段除外),但这只发生在测试代码中。它不会自动将实例注入到测试代码中。

您必须手动注入模拟实例。例如:

public class SomeTest
{
   @Autowired UnitUnderTest unitUnderTest;
   @Mocked ISomeInterface theMock; // created and assigned automatically

   @Test
   public void testSomeMethod()
   {
      Deencapsulation.setField(unitUnderTest, theMock);
      //proceed with unit test here
   }
}

mockit.Deencapsulation是一个基于反射的实用程序类,允许您调用私有方法,获取/设置字段等。

答案 1 :(得分:8)

您可以使用org.springframework.test.util.ReflectionTestUtils在您的测试用例中明确注入模拟的ISomeInterface

请参阅documentation

答案 2 :(得分:4)

通过上面提供的提示,这里是我发现最有用的JMockit新手:JMockit提供了Deencapsulation类,允许您设置私有依赖字段的值(无需拖动Spring库中的)和MockUp类,它允许您显式创建接口的实现并模拟接口的一个或多个方法。以下是我最终解决这个特殊情况的方法:

@Before
public void setUp() {

   IMarketMakerDal theMock = new MockUp <IMarketMakerDal>() {

      @Mock
      MarketMakerDcl findByMarketMakerGuid( String marketMakerGuid ) {

         MarketMakerDcl marketMakerDcl = new MarketMakerDcl();
         marketMakerDcl.setBaseCurrencyCode( CURRENCY_CODE_US_DOLLAR );
         return marketMakerDcl;
      }
   }.getMockInstance();

   setField( unitUnderTest, theMock );
}

感谢大家的帮助。

答案 3 :(得分:2)

对于那些见过的人

java.lang.IllegalStateException: Missing @Injectable for field *** 

java.lang.IllegalStateException: Missing @Tested class for field ***
jmockit(或@autowired)框架中使用spring模拟spring boot字段时出现

错误,我在以下两个步骤中做了以避免上述错误:

  1. 使用@Tested(fullyInitialized=true)代替@Tested
  2.   

    https://groups.google.com/forum/#!msg/jmockit-users/uo0S51lSX24/lQhLNN--eJcJ

    1. 将jmockit的版本还原为1.18或之前的版本
    2.   

      https://groups.google.com/forum/#!topic/jmockit-users/wMFZggsA8LM

答案 4 :(得分:0)

如果您有接口的@Qualifier注释,则需要将@Injectable字段命名为与限定符中命名的字段完全相同。

以下是JMockit doc的引用:

  

在查找匹配的@Injectable或@Tested值时,将使用在Java EE(@Resource(name),@ Name)或Spring框架(@Qualifier)的字段注释中指定的自定义名称。当这样的名字包含 - (短划线)或。 (点)字符,相反使用相应的驼峰名称。

例如:

@Component
public class AClass {

   @Autowired
   private Bean1 bean1;

   @Autowired
   @Qualifier("my-dashed-name")
   private AmqpTemplate rpcTemplate;
}

单元测试类:

public class AClassTest {

   @Injectable
   private Bean1 bean1;

   @Injectable
   private AmqpTemplate myDashedName;

   @Tested
   private AClass aClass = new AClass();
}

此外,不需要为每个@Autowired bean使用setFiled,所有字段在@Tested类实例化时自动注入。在JMockit ver上测试过。 1.30