Testing the behavior of the void method

Suppose I have the following utility object

public class UserService { @Autowired private UserDao dao; public void addUser(String username, String password) { if (username.length() < 8 ) { username = username + "random" ; // add some random string } User user = new User(username, password); dao.save(user); } } 

I want to check the behavior of the addUser method when the username is less than 8 and when the username is more than 8 char. How to approach unit test UserService.addUser (...) and check it? I know using assert (), but the password is not available outside the addUser (...) method.

I use JUnit and Mockito.

+8
java unit-testing junit mockito
source share
6 answers

I came up with a solution, after some re-visiting the problem again after a few months.

The idea is to observe the user object that is passed to the UserDao user. We can check the username value by doing this, therefore unit test code:

 @RunWith(MockitoJUnitRunner.class) public class UserServiceTest { @Mock private UserDao dao; @InjectMock private UserService service; @Test public void testAddingUserWithLessThan8CharUsername () { final String username = "some"; final String password = "user"; doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { Object[] args = invocationOnMock.getArguments(); User toBeSaved = (User) args[0]; Assert.assertEquals(username + "random", toBeSaved.getPassword()); return null; } }).when(userDao).save(Matchers.any(User.class)); service.addUser(username, password); } } 

Guillaume did have the closest answer, but he answered using jMock. However, he gave me an idea on how to do this, so I think he deserves some credit too.

+6
source share

You are testing side effects, but fortunately all you need is passed to dao.save (). First create a UserDao (with or without Mockito), then you can use ReflectionTestUtils to set the dao in the UserService, then you can check the values ​​that are passed to dao.save ().

Something like:

 private class TestUserDao extends UserDao { private User savedUser; public void save(User user) { this.savedUser = user; } } @Test public void testMethod() { UserService userService = new UserService(); TestUserDao userDao = new TestUserDao(); ReflectionTestUtils.setField(userService, "dao", userDao); userService.addUser("foo", "bar"); assertEquals("foo", userDao.savedUser.username.substring(0, 3)); assertEquals("bar", userDao.savedUser.password); } 

Or you can use Mockito to bully Dao if you want.

+1
source share

Use a mocking structure. The example below uses JMock2 , but it will be similar to EasyMock , Mockito , etc. In addition, you need to extract the username generation into something like UsernameGenmerator in order to mock it. You will need another special test for the username generator.

 private final Mockery mockery = new Mockery(); private final UserDao mockDao = mockery.mock(UserDao.class); private final UsernameGenerator mockUserNameGenerator = mockery.mock(UsernameGenerator.class); @Test public void addUserUsesDaoToSaveUser() { final String username = "something"; final String generatedUsername = "siomething else"; final String password = "a password"; mockery.checking(new Expectations() {{ oneOf(mockUsernameGenerator).generateUsername(username); will(returnValue(generatedUsername)); oneOf(mockDao).save(new User(generatedUsername, password)); // assumes your User class has a "natueral" equals/hashcode }}); UserService userService = new UserService(); userService.addUser(username, password); } 

And for UsernameGenerator you need to check the length of the returned username:

 @Test public void leavesUsernameUnchangedIfMoreThanEightChars() { final String username = "123456789"; final UsernameGenerator usernameGenerator = new UsernameGenerator(); assertEquals(username, userGenerator.generateUsername(username)); } @Test public void addsCharactersToUsernameIfLessThanEightChars() { final String username = "1234567"; final UsernameGenerator usernameGenerator = new UsernameGenerator(); assertEquals(8, userGenerator.generateUsername(username).length()); } 

Of course, depending on your β€œrandom” method, you can also check its specific behavior. In addition, the above provide sufficient coverage for your code.

+1
source share

It all depends on how you implement the DAO persistence method.

If you really store in a hard-coded repository, you probably need to query the repository itself for the values ​​you are interested in.

If you have a basic interface that is being called, then you should be able to configure the callback method and get the actual value that is saved.

I never used Mockito, so I could not give you the exact code that this article should contain:

Using Mockito, how do I intercept a void callback object?

0
source share

Consider extracting the username generation logic as a dependency on the UserService.

 interface UserNameGenerator { Strign generate(); } 

UserNameGenerator wire is the same as UserDao . And change the code to:

 public class UserService { @Autowired private UserDao dao; @Autowired private UserNameGenerator nameGenerator; public void addUser(String username, String password) { if (username.length() < 8 ) { username = nameGenerator.generate(); } User user = new User(username, password); dao.save(user); } } 

Then create a standard implementation of UserNameGenerator and move the name generation logic there.

Now you can easily check the behavior by taunting UserNameGenerator and UserDao .

To check use case when username is less than 8

 String username = "123"; String password = "pass"; String generatedName = "random"; // stub generator when(nameGenerator.generate()).thenReture(generatedName); // call the method userService.addUser(username, password); // verify that generator was called verify(nameGenerator).generate(); verify(userDao).save(new User(generatedName, password)); 

To check use case when username is longer than 8

 String username = "123456789"; String password = "pass"; String generatedName = "random"; // call the method userService.addUser(username, password); // verify that generator was never called verify(nameGenerator, never()).generate(); verify(userDao).save(new User(username, password)); 
0
source share

The easiest way is to extract the part where you have the username correction logic

 if (username.length() < 8 ) { username = username + "random" ; // add some random string } 

into the method and check the return value of this method.

 public string GetValidUsername(string userName){ if (username.length() < 8 ) { return username + "random" ; // add some random string } return username; } 

with this, you can pass different types of username and test the behavior of your code.

-one
source share

All Articles