Reputation:
I am developing an app and inside her I must write test class for my UserService class. This is my service class:
private static final Logger LOG = LoggerFactory.getLogger("userLogger");
@EJB
UserDAO userDAO;
@Override
public List<User> list() {
LOG.info("Get all users!");
return Optional.ofNullable(userDAO.findAll())
.orElse(Collections.emptyList()).stream().map(u -> u.toUser())
.collect(Collectors.toList());
}
@Override
public User findById(long id) {
UserEntity userEntity = userDAO.find((id));
if (userEntity == null) {
throw new UserNotFoundException(id);
}
LOG.info("User founded with id {}", id);
return userEntity.toUser();
}
@Override
public User create(User user) {
if (user == null) {
throw new ServiceException("Invalid request!");
}
UserEntity exists = userDAO.find(user.getId());
if (exists != null) {
throw new UserAlreadyExistsException(user.getId());
}
UserEntity userEntity = new UserEntity(user);
userDAO.create(userEntity);
LOG.info("Created user with id {}. Username is {}. Name is {}. Surname is {}. Email is {}.",
userEntity.getUserId(), userEntity.getUsername(), userEntity.getName(),
userEntity.getSurname(), userEntity.getEmail());
return userEntity.toUser();
}
@Override
public User update(long id, User user) {
if (user == null) {
throw new ServiceException("Invalid request!");
}
UserEntity userEntity = userDAO.find((id));
if (userEntity == null) {
throw new UserNotFoundException(id);
}
userEntity.update(user);
userDAO.update(userEntity);
return userEntity.toUser();
}
@Override
public void delete(long id) {
UserEntity userEntity = userDAO.find(id);
if (userEntity == null) {
throw new UserNotFoundException(id);
}
userDAO.delete(userEntity);
LOG.info("Deleted user with id {}", userEntity.getUserId());
}
This is my test class:
public class UserServiceImplementationTest {
private static User useric;
@Spy
@InjectMocks
UserService userService;
@Mock
UserDAO userDAO;
@BeforeMethod
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
UserEntity userEntity = mock(UserEntity.class);
willReturn(mock(User.class)).given(userEntity).toUser();
willReturn(userEntity).given(userDAO).find(1L);
useric = new User(7, "DDD", "SDSDS", "SAAsd", "[email protected]");
}
@Test
public void testWhenUserExist() throws Exception {
// GIVEN
long userId = 0;
// WHEN
User user = userService.findById(userId);
// THEN
assertNotNull(user);
Assert.assertEquals(userId, user.getId());
//verify(userService, Mockito.times(1)).findById(userId);
}
@Test(expectedExceptions = ServiceException.class, expectedExceptionsMessageRegExp = "user-service: User with id: 35 was not found!")
public void testWhenUserNotExist() throws Exception {
// GIVEN
long userId = 35;
// WHEN
userService.findById(userId);
// THEN
fail();
}
@Test
public void testCreateUser() throws Exception{
User user = userService.create(useric);
assertNotNull(user);
Assert.assertEquals(useric.getName(), user.getName());
//User userEntity = new User(1, "aaaewwe", "bbbb", "abba", "[email protected]");
//User user = userService.create(userEntity);
// Assert.assertEquals(user, user);
//assertNotNull(user);
// Assert.assertEquals(userEntity, user);
// verify(userService, Mockito.times(1)).create(userEntity);
}
@Test
public void testDeleteUser() throws Exception{
long userId = 1;
userService.delete(userId);
verify(userService, Mockito.times(1)).delete(userId);
}
}
And when I run this code I get this error:
main] INFO userLogger - Created user with id 7. Username is DDD. Name is SAAsd. Surname is SDSDS. Email is [email protected].
[main] INFO userLogger - Deleted user with id 0
PASSED: testCreateUser
PASSED: testDeleteUser
PASSED: testWhenUserNotExist
FAILED: testWhenUserExist
com.comtrade.trips.service.user.exception.UserNotFoundException: user-service: User with id: 0 was not found!
at com.comtrade.trips.service.user.UserService.findById(UserService.java:45)
at com.comtrade.trips.service.user.UserServiceImplementationTest.testWhenUserExist(UserServiceImplementationTest.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:645)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:756)
at org.testng.TestRunner.run(TestRunner.java:610)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:387)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:382)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
at org.testng.SuiteRunner.run(SuiteRunner.java:289)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1293)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1218)
at org.testng.TestNG.runSuites(TestNG.java:1133)
at org.testng.TestNG.run(TestNG.java:1104)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:132)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:236)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:81)
===============================================
Default test
Tests run: 4, Failures: 1, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 4, Failures: 1, Skips: 0
===============================================
[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@23986957: 21 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 13 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@1a04f701: 79 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@12b0404f: 10 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter2@7c469c48: 9 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1677d1: 41 ms
I am not stupid, I know what that error means but could someone tells are syntax (and logic) of my test methods good and how to write method for testUserExist method?
Thanks in advance
EDIT: when I have changed my test methods my test class is now like this:
private static User useric;
@Spy
@InjectMocks
UserService userService;
@Mock
UserDAO userDAO;
@BeforeMethod
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
UserEntity userEntity = mock(UserEntity.class);
willReturn(mock(User.class)).given(userEntity).toUser();
//willReturn(userEntity).given(userDAO).find(0L);
//useric = new User(7, "DDD", "SDSDS", "SAAsd", "[email protected]");
}
@Test
public void testWhenUserExist() throws Exception {
User goran = new User(5, "goran1992", "goran", "palibrk", "[email protected]");
User user = userService.create(goran);
// GIVEN
//long userId = 0;
// WHEN
// user = userService.findById(goran.getId());
// THEN
assertNotNull(user);
Assert.assertEquals(user.getId(), goran.getId());
//verify(userService, Mockito.times(1)).findById(userId);
}
@Test(expectedExceptions = ServiceException.class, expectedExceptionsMessageRegExp = "user-service: User with id: 35 was not found!")
public void testWhenUserNotExist() throws Exception {
// GIVEN
long userId = 35;
// WHEN
userService.findById(userId);
// THEN
fail();
}
@Test
public void testCreateUser() throws Exception{
User user = userService.create(useric);
assertNotNull(user);
Assert.assertEquals(useric.getName(), user.getName());
//User userEntity = new User(1, "aaaewwe", "bbbb", "abba", "[email protected]");
//User user = userService.create(userEntity);
// Assert.assertEquals(user, user);
//assertNotNull(user);
// Assert.assertEquals(userEntity, user);
// verify(userService, Mockito.times(1)).create(userEntity);
}
@Test
public void testDeleteUser() throws Exception{
//long userId = 1;
userService.delete(useric.getId());
verify(userService, Mockito.times(1)).delete(useric.getId());
}
And my console gives me this error:
[main] INFO userLogger - Created user with id 5. Username is goran1992. Name is palibrk. Surname is goran. Email is [email protected].
PASSED: testWhenUserExist
PASSED: testWhenUserNotExist
FAILED: testCreateUser
com.comtrade.trips.common.ServiceException: Invalid request!
at com.comtrade.trips.service.user.UserService.create(UserService.java:54)
at com.comtrade.trips.service.user.UserServiceImplementationTest.testCreateUser(UserServiceImplementationTest.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:645)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:756)
at org.testng.TestRunner.run(TestRunner.java:610)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:387)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:382)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
at org.testng.SuiteRunner.run(SuiteRunner.java:289)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1293)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1218)
at org.testng.TestNG.runSuites(TestNG.java:1133)
at org.testng.TestNG.run(TestNG.java:1104)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:132)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:236)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:81)
FAILED: testDeleteUser
java.lang.NullPointerException
at com.comtrade.trips.service.user.UserServiceImplementationTest.testDeleteUser(UserServiceImplementationTest.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:645)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:756)
at org.testng.TestRunner.run(TestRunner.java:610)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:387)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:382)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
at org.testng.SuiteRunner.run(SuiteRunner.java:289)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1293)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1218)
at org.testng.TestNG.runSuites(TestNG.java:1133)
at org.testng.TestNG.run(TestNG.java:1104)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:132)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:236)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:81)
===============================================
Default test
Tests run: 4, Failures: 2, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 4, Failures: 2, Skips: 0
===============================================
[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@2cbb3d47: 22 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 28 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@29176cc1: 73 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@77167fb7: 11 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter2@18ce0030: 12 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@25d250c6: 51 ms
Upvotes: 0
Views: 126
Reputation: 131326
Why do you want to mock and spy the class under test ?
A clean unit test should test the implementation as natural as possible and mock only dependencies.
Of course, you can have some exception but in your case, I don't see any things that justifying makes the test logic less straight.
In your case, the single thing you want really to mock is the dependency on UserDAO
that UserService
has.
The remain should be the real and natural implementation.
Besides, you also mock entities retrieved by the DAO. The logic of your test is hard to understand.
At last, the general setup() executed before each tested method does too many things : it simulates already some particular behaviors. The recording specific mock behavior should be performed as required.
To test the findById
method when the user exists, I propose you to mock only the behavior of the UserDAO when you retrieve a UserEntity.
Then, what you want to check is that the actual user retrieved matches with which you have provided in the mock recording.
In this way, you check two things :
toUser()
method on the UserEntity
retrieved by the DAO.Of course, user should override equals() and hashCode() to this assertion has sense :
Assert.assertEquals(actualUser, userEntityByMock.toUser());
Or you could check fields by fields or use reflection.
Here is a snippet :
@Mock
private UserDAO userDAOMock;
private UserEntity userEntityByMock;
private UserService service;
@BeforeMethod
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
// You should add a constructor with a arg for that but you could use
// reflection to inject the mock if you don't want to open the api of
// the class
service = UserService(userDAOMock);
userEntityByMock = new UserEntity(1, "DDD", "SDSDS", "SAAsd", "[email protected]");
}
@Test
public void findByIdWhenTheUserExists() throws Exception {
// GIVEN
long userId = 1;
Mockito.when(userDAOMock.find(userId)).thenReturn(userEntityByMock);
// WHEN
User actualUser = userService.findById(userId);
// THEN
Assert.assertEquals(actualUser, userEntityByMock.toUser());
}
Upvotes: 0
Reputation: 15622
in you setup you configure
willReturn(userEntity).given(userDAO).find(1L);
therefore you get a null
from your userDAO
for ID 0
You should either change the setup to use anyLong()
(or Easymocks equivalent to it) instead of 1L
or add the correct userDAO
configuration to your test method:
@Test
public void testWhenUserExist() throws Exception {
// GIVEN
long userId = 0;
willReturn(userEntity).given(userDAO).find(userId);
// WHEN
// ...
}
Upvotes: 0
Reputation: 1990
Obviously the user with id
1 doesn't exist when the test testWhenUserExist()
runs. If you create the user in this method first and then check if he exists, this should work (and you avoid side-effects if you ever change your setUp()
method). It looks like you create a user with id
7 in your setUp()
method.
Upvotes: 0