I have a component setup that is essentially a launcher for an application. It is configured like so:
@Component public class MyLauncher { @Autowired MyService myService; //other methods }
MyService is annotated with the @Service
Spring annotation and is autowired into my launcher class without any issues.
I would like to write some jUnit test cases for MyLauncher, to do so I started a class like this:
public class MyLauncherTest private MyLauncher myLauncher = new MyLauncher(); @Test public void someTest() { } }
Can I create a Mock object for MyService and inject it into myLauncher in my test class? I currently don't have a getter or setter in myLauncher as Spring is handling the autowiring. If possible, I'd like to not have to add getters and setters. Can I tell the test case to inject a mock object into the autowired variable using an @Before
init method?
If I'm going about this completely wrong, feel free to say that. I'm still new to this. My main goal is to just have some Java code or annotation that puts a mock object in that @Autowired
variable without me having to write a setter method or having to use an applicationContext-test.xml
file. I would much rather maintain everything for the test cases in the .java
file instead of having to maintain a separate application content just for my tests.
I am hoping to use Mockito for the mock objects. In the past I have done this by using org.mockito.Mockito
and creating my objects with Mockito.mock(MyClass.class)
.
The Spring Framework does allow you to autowire private fields. You do see people doing this. And Spring will perform some reflection magic to perform dependency injection.
I would generally NOT use @Autowired for private fields or methods. @Autowired means, somebody from outside will set this field. "Private" on the other hand means nobody except this class is allowed to use it.
To check the Service class, we need to have an instance of the Service class created and available as a @Bean so that we can @Autowire it in our test class. We can achieve this configuration using the @TestConfiguration annotation.
Also note that we can wire other spring beans in our jUnit test classes using @Autowired annotation.
You can absolutely inject mocks on MyLauncher in your test. I am sure if you show what mocking framework you are using someone would be quick to provide an answer. With mockito I would look into using @RunWith(MockitoJUnitRunner.class) and using annotations for myLauncher. It would look something like what is below.
@RunWith(MockitoJUnitRunner.class) public class MyLauncherTest @InjectMocks private MyLauncher myLauncher = new MyLauncher(); @Mock private MyService myService; @Test public void someTest() { } }
The accepted answer (use MockitoJUnitRunner
and @InjectMocks
) is great. But if you want something a little more lightweight (no special JUnit runner), and less "magical" (more transparent) especially for occasional use, you could just set the private fields directly using introspection.
If you use Spring, you already have a utility class for this : org.springframework.test.util.ReflectionTestUtils
The use is quite straightforward :
ReflectionTestUtils.setField(myLauncher, "myService", myService);
The first argument is your target bean, the second is the name of the (usually private) field, and the last is the value to inject.
If you don't use Spring, it is quite trivial to implement such a utility method. Here is the code I used before I found this Spring class :
public static void setPrivateField(Object target, String fieldName, Object value){ try{ Field privateField = target.getClass().getDeclaredField(fieldName); privateField.setAccessible(true); privateField.set(target, value); }catch(Exception e){ throw new RuntimeException(e); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With