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
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
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.
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:
@Tested(fullyInitialized=true)
instead of @Tested
https://groups.google.com/forum/#!msg/jmockit-users/uo0S51lSX24/lQhLNN--eJcJ
1.18
or previous oneshttps://groups.google.com/forum/#!topic/jmockit-users/wMFZggsA8LM
You can use org.springframework.test.util.ReflectionTestUtils
to explicitly inject your mocked ISomeInterface
in your test case.
See documentation
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.