user6450105
user6450105

Reputation:

Why does my test fail?

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

Answers (3)

davidxxx
davidxxx

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 :

  • the dao is called with the expected id parameter (this is called since it return the mocked data which is returned only if you provide the expected id parameter)
  • the service applies as expected the 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

Timothy Truckle
Timothy Truckle

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

user7291698
user7291698

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

Related Questions