Using JMockit to mock autowired interface implementations

前端 未结 5 439
暖寄归人
暖寄归人 2020-12-17 18:10

We are writing JUnit tests for a class that uses Spring autowiring to inject a dependency which is some instance of an interface. Since the class under test never explicitly

相关标签:
5条回答
  • 2020-12-17 18:38

    If you have a @Qualifier annotation for the interface, you need to name your @Injectable field exactly as it is named in qualifier.

    Here is quote from JMockit doc:

    Custom names specified in field annotations from Java EE (@Resource(name), @Named) or the Spring framework (@Qualifier) are used when looking for a matching @Injectable or @Tested value. When such a name contains a - (dash) or . (dot) character, the corresponding camel-cased name is used instead.

    For example:

    @Component
    public class AClass {
    
       @Autowired
       private Bean1 bean1;
    
       @Autowired
       @Qualifier("my-dashed-name")
       private AmqpTemplate rpcTemplate;
    }
    

    Unit test class:

    public class AClassTest {
    
       @Injectable
       private Bean1 bean1;
    
       @Injectable
       private AmqpTemplate myDashedName;
    
       @Tested
       private AClass aClass = new AClass();
    }
    

    Also there is no need to use setFiled for each @Autowired bean, all fields injects automatically when @Tested class instantiated. Tested on JMockit ver. 1.30

    0 讨论(0)
  • 2020-12-17 18:40

    JMockit will always instantiate a mocked interface (except in the case of a final mock field), but that only occurs in test code. It will not automatically inject the instance into code under test.

    You would have to manually inject the mock instance. For example:

    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 is a Reflection-based utility class that lets you invoke private methods, get/set fields, etc.

    0 讨论(0)
  • 2020-12-17 18:41

    For those people who met

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

    or

    java.lang.IllegalStateException: Missing @Tested class for field ***
    

    error when using jmockit to mock @autowired field in spring ( or spring boot) framework, I did below two steps to avoid above errors:

    1. use @Tested(fullyInitialized=true) instead of @Tested

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

    1. revert jmockit's version back to 1.18 or previous ones

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

    0 讨论(0)
  • 2020-12-17 18:50

    You can use org.springframework.test.util.ReflectionTestUtils to explicitly inject your mocked ISomeInterface in your test case.

    See documentation

    0 讨论(0)
  • 2020-12-17 18:53

    With the hints kindly provided above, here's what I found most useful as someone pretty new to JMockit: JMockit provides the Deencapsulation class to allow you to set the values of private dependent fields (no need to drag the Spring libraries in), and the MockUp class that allows you to explicitly create an implementation of an interface and mock one or more methods of the interface. Here's how I ended up solving this particular case:

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

    Thanks everyone for the help.

    0 讨论(0)
提交回复
热议问题