Testing fields which are going to be initialized by field injection (CDI) - java

let's assume we've got the following snippet as part of an full Java EE application:
#Singleton
public class LoginService {
#Inject
private UserDAO userDAO;
protected boolean login(String username, String password){
// [...]
User user = userDAO.findByUsername(username);
// [...]
}
}
UserDAO is an interface and there's one specific class implementation of that interface called DatabaseUserDAO which is injected into the userDAO field.
Now I am going to write a test for the login method e. g. testLoginSuccessfulIfLoginDataCorrect(). But as I don't want to depend on the database I just want to stub it by using a class e.g. public class TestUserDAO implements UserDAOand inject this one instead of the default class which whould be injected. What are the possibilities to implement it? Let's also assume that there is no constructor injection or other ways to initialize the field.

Use arquillian (http://arquillian.org/) along with mockito (http://site.mockito.org/) or one of its derivates to:
create a mockup of UserDAO to inject
create a bundle from your class under test along with the mock
create a junit test which gets your LoginService along with the mock injected and can use it for tests:
Example (modified from actual code to somewhat match your class names):
(Attention: this kind of deployment generation only works for maven projects)
#RunWith(Arquillian.class)
public class LoginSeviceTest {
// a pattern I find quite neat: hold the mocks in a static local class, but they might be anywhere else
public static class LocalMocks {
#Produces public static UserDAO mockUser = Mockito.mock(UserDAO.class);
}
#Deployment
public static WebArchive createDeployment() {
PomEquippedResolveStage pom = Maven.resolver().loadPomFromFile("pom.xml");
BeansDescriptor beansXml = Descriptors.create(BeansDescriptor.class)
.addDefaultNamespaces().getOrCreateAlternatives()
.up();
WebArchive jar = ShrinkWrap.create(WebArchive.class)
.addAsLibraries(pom.resolve("org.mockito:mockito-core").withTransitivity().asFile())
.addClass(LoginService.class) // eventually further classes or packages you depend on
.addClass(LoginSeviceTest.LocalMocks.class)
.addAsWebInfResource(new StringAsset(beansXml.exportAsString()), "beans.xml");
return jar;
}
#Inject LoginService loginService;
#Test
public void testLogin() {
// use the injected loginService here for actual tests
}
}
Note, that you do not need to change the class under test this way to make testing possible.

Well, there are not secret for that.
You have four possibilities.
Create a constructor for all DAOs (EJBs).
#Singleton
public class LoginService {
#Inject
private UserDAO userDAO;
LoginService (UserDAO userDAO) {
this.userDAO = userDAO;
}
}
Create a set for each DAO.
#Singleton
public class LoginService {
#Inject
private UserDAO userDAO;
setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
Set the variable directly with default access
#Singleton
public class LoginService {
#Inject
UserDAO userDAO;
}
And in your test:
loginService.userDAO = userDAOMocked.
So, you can mock the UserDAO and pass to the LoginService test as parameter using the constructor or by setter.
Another one is by reflection (without constructor or setter), but I dislike this approach...:
Reflection
public static void setPrivateField(Class<? extends Object> instanceFieldClass, Object instance, String fieldName, Object fieldValue) throws Exception {
Field setId = instanceFieldClass.getDeclaredField(fieldName);
setId.setAccessible(true);
setId.set(instance, fieldValue);
}
And to use:
setPrivateField(loginService, "userDAO", userDAOMocked);

Related

Feign client unit test

I would like to know what is the best way to write unit tests in this context :
MyApi :
#RestController
public class MyApi{
#Autowired
MyAction myAction;
#PostMapping
public ResponseEntity addAction(#ResponseBody MyDto myDto){
return myAction.addAction(myDto);
}
}
MyAction :
#Service
public class MyAction{
#Autowired
private MyClient myClient;
public ResponseEntity<AuthenticationResponseDto> login(MyDto myDto{
return ResponseEntity.ok(myClient.addClient(myDto));
}
}
For example, is it mandatory to add constructor ?
Thanks
It's considered a good practice to use constructor injection, however if you don't want to use it you need to use #Mock and #InjectMocks. It uses reflection and constructor is not required to be defined.
#RunWith(MockitoJUnitRunner.class)
public class Test {
#Mock
private Client client;
#InjectMocks
private ServiceImpl plannerService = new ServiceImpl();
#Test
public void test() throws Exception {
....
}
}
I'm sure there is a way to avoid using an autowired constructor and just autowiring a field, however I use constructors as I consider it a good practice. It also makes it easy to inject a mocked object like so
#Mock
MyAction myAction;
MyApi myApi;
ResponseEntity<AuthenticationResponseDto> testResponse = ResponseEntity.ok
(new AuthenticationResponseDto());
#Before
public void setup(){
myApi = new MyApi(myAction);
}
#Test
public void simpleMyApiTestExample (){
when(myAction.login(any())).thenAnswer(i-> testRespone);
ResponseEntity<?> actualResponse = myApi.addAction(new MyDto());
assertThat(actualResponse).isSameAs(testResponse);
}
Just to give you an idea. I just wrote this example in the SO text editor, so appologies for any typos/mistakes. But hopefully this shows why having constructors is useful for testing things that are autowired. It allows you to mock the objects necessary for instantiation by adding them to the constructor. In this example this would probably also apply to MyDto and AuthenticationResponseDto objects as well.

Unit test of Spring boot service with private fields and #PostConstruct

I have a Spring boot service defined like this
#Service
public class MyService {
private String field1;
private String field2;
#Autowired
private AnotherService anotherService
#PostConstruct
public void init() {
anotherService.initField1(field1);
anotherService.initField2(field2);
}
public String foo() {
return field1 + field2;
}
}
How should I write a unit test for foo. Well, it's more about how to deal with class fields and the PostConstruct methods.
Thanks!!
EDIT:
Added AnotherService as a field as well.
The following example shows a #Service Bean that uses constructor injection to obtain a required AnotherService bean:
#Service
public class MyService {
private String field1;
private String field2;
private final AnotherService anotherService;
public MyService(AnotherService anotherService) {
this.anotherService = anotherService;
this.anotherService.initField1(field1);
this.anotherService.initField2(field2);
}
public String foo() {
return field1 + field2;
}
}
Note you can omit the #Autowired becuase MyService has one constructor. See here for more info.
testing with Spring
Use the #RunWith(SpringRunner.class) and #SpringBootTest to inject MyService and start using it:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyServiceTest {
#Autowired
private MyService service;
#Test
public void testFoo() {
String expResult = "";
String result = service.foo();
assertEquals(expResult, result);
}
}
testing without Spring
public class MyServiceTest2 {
private MyService service;
#Before
public void setUp() {
service = new MyService(new AnotherService.Fake());
}
#Test
public void testFoo() {
String expResult = "";
String result = service.foo();
assertEquals(expResult, result);
}
}
Here Fake is a fake implementation of the AnotherService interface which allows you to have a pure unit test.
Writing good, testable code can be hard. There are some pitfalls waiting for everyone to fall into sooner or later.
As a rule of thumb, try to avoid field level injection, use constructor parameter injection instead:
#Service
public class MyService {
private AnotherService anotherService;
#Autowired
MyService (AnotherService anotherService) {
this.anotherService = anotherService;
}
}
This is the cleanest solution. You can call the constructor from your tests, spring will inject dependencies the same way at runtime. So there is no difference to deal with.
The same goes for any life cycle constructs like #PostConstruct. If you can avoid them, do it. Let the constructor handle it. If you absolutely have to keep them around, well, the only logical solution is to manually call them from your test code.
Now, how to setup services that at runtime would be autowired by the container?
For unit testing, you basically have three options (in no particular order):
If the required service is rather simple and can easily be constructed, create and pass it as the framework would do.
If the service has a limited interface that does not change too often, create a fake service.
Use a mocking lib like mockito (spring-boot-test provides it by default).

unit test a interface implementation with mock in Spring Boot

I'm trying to write a simple unit test for a service in Spring Boot.
The service calls a method on a repository which returns an instance of User.
I'm trying to mock the repository, because I want to test only the service.
So, the code for Repository:
public interface UserRepository extends MongoRepository<User, String> {
User findByEmail(String email);
}
Service interface:
public interface UserService {
#Async
CompletableFuture<User> findByEmail(String email) throws InterruptedException;
}
Service implementation:
#Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
// dependency injection
// don't need Autowire here
// https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-spring-beans-and-dependency-injection.html
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Async
public CompletableFuture<User> findByEmail(String email) throws InterruptedException {
User user = userRepository.findByEmail(email);
return CompletableFuture.completedFuture(user);
}
}
Unit Test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class UserServiceTest {
#InjectMocks
UserService userService;
#Mock
UserRepository mockUserRepository;
#Before
public void setUp() {
MockitoAnnotations.initMock(this);
}
#Test
public void mustReturnUser() throws InterruptedException {
String emailTest = "foo#bar.com";
User fakeUser = new User();
fakeUser.setEmail(emailTest);
when(mockUserRepository.findByEmail(emailTest)).thenReturn(fakeUser);
User user = userService.findByEmail(emailTest).join();
assertThat(user).isEqualTo(fakeUser);
verify(mockUserRepository).findByEmail(emailTest);
}
}
When I run this test, I got a MockitoException:
org.mockito.exceptions.base.MockitoException:
Cannot instantiate #InjectMocks field named 'userService'.
...
Caused by: org.mockito.exceptions.base.MockitoException: the type 'UserService' is an interface.
Instead of using the interface, I tried to use the real implementation; changing the test like this:
#InjectMocks
UserServiceImpl userService;
Now, the test passes with success, but this don't appear be right (at least for me).
I like to test the UserService that Spring Boot is using (suppose that in a new version of my system, I implement a new UserServicePostgreSQLImpl - now I'm using MongoDB).
(edit: see the bottom edit in the question)
I changed the Unit Test as follows:
#Autowired
#InjectMocks
UserService userService;
but now I got a test failure:
Expected :model.User#383caf89
Actual :null
For some reason, when I use #Autowired, the UserRepository mock doesn't work.
If I change the emailTest to use a real email in my database,
the test passes.
When I use #Autowired,
the test is using the real UserRepository and not a Mock version of UserRepository.
Any help?
Edit: looking at the answers from #msfoster and #dunni, and thinking better, I believe that the correct way is to test every implementation (in my example, use UserServiceImpl userService).
In order for your UserServiceImpl to be autowired when annotating it with #InjectMocks then it needs to registered as a Spring bean itself. You can do this most simply by annotating your UserServiceImpl class with #Service.
This will ensure it is picked up by the component scan in your Spring boot configuration. (As long as the scan includes the package your service class is in!)
You are running your tests with SpringRunner but for mocks you don't really need spring context. Try following code
// Using mockito runner
#RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
#Mock
UserRepository mockUserRepository;
// Mockito will auto inject mockUserRepository mock to userService via constructor injection
#InjectMocks
UserService userService;
#Test
public void mustReturnUser() throws InterruptedException {
String emailTest = "foo#bar.com";
User fakeUser = new User();
fakeUser.setEmail(emailTest);
when(mockUserRepository.findByEmail(emailTest)).thenReturn(fakeUser);
User user = userService.findByEmail(emailTest).join();
assertThat(user).isEqualTo(fakeUser);
verify(mockUserRepository).findByEmail(emailTest);
}
}
This is just a variation on the #Yogesh Badke answer.
Although you are using spring at runtime,
there is no need to use spring during the unit test.
Instead,
you can mock all the dependencies and set them to the mocks during test setup
(using reflection or setters, if you have them).
Here is some example code:
import org.springframework.test.util.ReflectionTestUtils;
public class TestUserService
{
private static final String VALUE_EMAIL = "test email value";
private UserService classToTest;
#Mock
private User mockUser;
#Mock
private UserRepository mockUserRepository;
#Before
public void beforeTest()
{
MockitoAnnotations.initMock(this);
classToTest = new UserService();
doReturn(mockUser).when(mockUserRepository).findByEmail(VALUE_EMAIL);
ReflectionTestUtils.setField(
classToTest,
"userRepository",
mockUserRepository);
}
#Test
public void findByEmail_goodEmailInput_returnsCorrectUser()
{
final User actualResult;
actualResult = classToTest.findByEmail(VALUE_EMAIL);
assertSame(
mockUser,
actualResult);
}
}
If interface is implemented by more than one class, then use the qualifier name (example below) in Junit beans.xml file to run the respective Junit test case.
Example:
#Autowired
#Qualifier("animal")
private Animal animals;
In Junit beans.xml
<bean id="animal" class="com.example.abc.Lion"/>
where Lion is the implementation class for the Interface Animal.
You need to #InjectMocks for the implementation class. Not the interface class.
Example:
#RunWith(SpringRunner.class)
#SpringBootTest
public class UserServiceTest {
#Mock
UserRepository mockUserRepository;
#InjectMocks
UserServiceImpl userServiceImpl; ------> This is important
}

Injecting #Autowired private field during testing

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).
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);
}
}
Sometimes you can refactor your #Component to use constructor or setter based injection to setup your testcase (you can and still rely on #Autowired). Now, you can create your test entirely without a mocking framework by implementing test stubs instead (e.g. Martin Fowler's MailServiceStub):
#Component
public class MyLauncher {
private MyService myService;
#Autowired
MyLauncher(MyService myService) {
this.myService = myService;
}
// other methods
}
public class MyServiceStub implements MyService {
// ...
}
public class MyLauncherTest
private MyLauncher myLauncher;
private MyServiceStub myServiceStub;
#Before
public void setUp() {
myServiceStub = new MyServiceStub();
myLauncher = new MyLauncher(myServiceStub);
}
#Test
public void someTest() {
}
}
This technique especially useful if the test and the class under test is located in the same package because then you can use the default, package-private access modifier to prevent other classes from accessing it. Note that you can still have your production code in src/main/java but your tests in src/main/test directories.
If you like Mockito then you will appreciate the MockitoJUnitRunner. It allows you to do "magic" things like #Manuel showed you:
#RunWith(MockitoJUnitRunner.class)
public class MyLauncherTest
#InjectMocks
private MyLauncher myLauncher; // no need to call the constructor
#Mock
private MyService myService;
#Test
public void someTest() {
}
}
Alternatively, you can use the default JUnit runner and call the MockitoAnnotations.initMocks() in a setUp() method to let Mockito initialize the annotated values. You can find more information in the javadoc of #InjectMocks and in a blog post that I have written.
I believe in order to have auto-wiring work on your MyLauncher class (for myService), you will need to let Spring initialize it instead of calling the constructor, by auto-wiring myLauncher. Once that is being auto-wired (and myService is also getting auto-wired), Spring (1.4.0 and up) provides a #MockBean annotation you can put in your test. This will replace a matching single beans in context with a mock of that type. You can then further define what mocking you want, in a #Before method.
public class MyLauncherTest
#MockBean
private MyService myService;
#Autowired
private MyLauncher myLauncher;
#Before
private void setupMockBean() {
doNothing().when(myService).someVoidMethod();
doReturn("Some Value").when(myService).someStringMethod();
}
#Test
public void someTest() {
myLauncher.doSomething();
}
}
Your MyLauncher class can then remain unmodified, and your MyService bean will be a mock whose methods return values as you defined:
#Component
public class MyLauncher {
#Autowired
MyService myService;
public void doSomething() {
myService.someVoidMethod();
myService.someMethodThatCallsSomeStringMethod();
}
//other methods
}
A couple advantages of this over other methods mentioned is that:
You don't need to manually inject myService.
You don't need use the Mockito runner or rules.
I'm a new user for Spring. I found a different solution for this. Using reflection and making public necessary fields and assign mock objects.
This is my auth controller and it has some Autowired private properties.
#RestController
public class AuthController {
#Autowired
private UsersDAOInterface usersDao;
#Autowired
private TokensDAOInterface tokensDao;
#RequestMapping(path = "/auth/getToken", method = RequestMethod.POST)
public #ResponseBody Object getToken(#RequestParam String username,
#RequestParam String password) {
User user = usersDao.getLoginUser(username, password);
if (user == null)
return new ErrorResult("Kullanıcıadı veya şifre hatalı");
Token token = new Token();
token.setTokenId("aergaerg");
token.setUserId(1);
token.setInsertDatetime(new Date());
return token;
}
}
And this is my Junit test for AuthController. I'm making public needed private properties and assign mock objects to them and rock :)
public class AuthControllerTest {
#Test
public void getToken() {
try {
UsersDAO mockUsersDao = mock(UsersDAO.class);
TokensDAO mockTokensDao = mock(TokensDAO.class);
User dummyUser = new User();
dummyUser.setId(10);
dummyUser.setUsername("nixarsoft");
dummyUser.setTopId(0);
when(mockUsersDao.getLoginUser(Matchers.anyString(), Matchers.anyString())) //
.thenReturn(dummyUser);
AuthController ctrl = new AuthController();
Field usersDaoField = ctrl.getClass().getDeclaredField("usersDao");
usersDaoField.setAccessible(true);
usersDaoField.set(ctrl, mockUsersDao);
Field tokensDaoField = ctrl.getClass().getDeclaredField("tokensDao");
tokensDaoField.setAccessible(true);
tokensDaoField.set(ctrl, mockTokensDao);
Token t = (Token) ctrl.getToken("test", "aergaeg");
Assert.assertNotNull(t);
} catch (Exception ex) {
System.out.println(ex);
}
}
}
I don't know advantages and disadvantages for this way but this is working. This technic has a little bit more code but these codes can be seperated by different methods etc. There are more good answers for this question but I want to point to different solution. Sorry for my bad english. Have a good java to everybody :)
Look at this link
Then write your test case as
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"/applicationContext.xml"})
public class MyLauncherTest{
#Resource
private MyLauncher myLauncher ;
#Test
public void someTest() {
//test code
}
}

How to mock a private dao variable?

I have a dao.create() call that I want to mock when testing a method.
But I am missing something as I'm still getting NPE. What is wrong here?
class MyService {
#Inject
private Dao dao;
public void myMethod() {
//..
dao.create(object);
//
}
}
How can I mock out the dao.create() call?
#RunWith(PowerMockRunner.class)
#PrepareForTest(DAO.class)
public void MyServiceTest {
#Test
public void testMyMethod() {
PowerMockito.mock(DAO.class);
MyService service = new MyService();
service.myMethod(); //NPE for dao.create()
}
}
You are not injecting the DAO. With mockito you can change your test class to use #InjectMocks and use mockito runner.
#RunWith(MockitoJUnitRunner.class)
public void MyServiceTest {
#Mock
private Dao dao;
#InjectMocks
private MyService myService;
...
}
You can read more about InjectMocks at Inject Mocks API
Simpler way is changing your injection to injection by constructor. For example, you would change MyService to
class MyService {
...
private final Dao dao;
#Inject
public MyService(Dao dao) {
this.dao = dao;
}
...
}
then your test you could simple pass the mocked DAO in setup.
...
#Mock
private Dao dao;
#Before
public void setUp() {
this.dao = mock(Dao.class);
this.service = new MyService(dao);
}
...
now you can use verify to check if create was called, like:
...
verify(dao).create(argThat(isExpectedObjectBeingCreated(object)));
}
private Matcher<?> isExpectedObjectBeingCreated(Object object) { ... }
Using injection by constructor will let your dependencies clearer to other developers and it will help when creating tests :)
You still need to set the dao field with your mock.
You can use reflection to this.
You need to inject/set the mocked object DAO in your service class.
If it is a spring based project, you may have a look # Spring Junit Testrunner
If you use new MyService() the Dao is never injected. For the Dao to be injected you need to load the MyService via an ApplicationContext (Spring) or an Injector (Guice). Like you would in your normal application.
As others have already said, you need to set the dao field in your MyService class in some fashion. I'm unsure the mechanism to allow for a compound runner on your test to use both Powermock and a DI framework runner (assuming Powermock is required), but as long as you're already using PowerMock (for reasons unclear in the given example), you could avail yourself of the Whitebox class to set the dao more manually.
public void testMyMethod() {
Dao dao = mock(Dao.class)
doNothing().when(dao).create(anyObject())); //assuming no return val for dao.create()
MyService service = new MyService();
Whitebox.setInternalState(service, "dao", dao);
service.myMethod();
}

Categories