-2

Hello I have a method adding persons to teams. I want to write a test for this method but i'm newbie in junit/mockito test so i have many problems: This is my add method:

@Transactional
public void addPersonsToTeams(Long teamId, Long personId) {
    Assert.notNull(personId, "Object can't be null!");
    Assert.notNull(teamId, "Object can't be null!");
    try {
        Person person = personRepository.getOne(personId);
        Team team = teamRepository.getOne(teamId);
        person.getTeams().add(team);
        personRepository.save(person);
    } catch (Exception e) {
        throw new CreateEntityException();
    }

}

There is relation between this two entities(people/teams) And this is my test code but it doesn't work:

@Test
    public void shouldAddPersonToTeam(){
        Team team = new Team(1l, "TestCase1", "Description1", "Krakow", 12);
        Person person = new Person(1L, "jan", "mucha", "krakow", "email1@onet.com", "Programing", "Developer");

        teamService.createTeam(mapper.map(team, TeamDto.class));
        personService.addPerson(mapper.map(person, PersonDto.class));

        teamService.addPersonsToTeams(team.getId(), person.getId());

        verify(teamRepository, times(1)).save(team);
        verify(personRepository, times(1)).save(person);


    }

Mock konfiguration :

public class TeamServiceTest {
    private TeamService teamService;
    private ModelMapper mapper;
    private PersonService personService;

    @Mock
    private TeamRepository teamRepository;
    private PersonRepository personRepository; //-this is never assigned :/

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        this.mapper = new ModelMapper();
        teamService = new TeamService(teamRepository, this.mapper);
        personService = new PersonService(personRepository, this.mapper);

    }

1 Answers1

1

Your problem is the lines

Person person = personRepository.getOne(personId);
Team team = teamRepository.getOne(teamId);

in the method that you're testing. In your unit test for addPersonsToTeams, you don't want to test the behaviour of the two getOne methods. That's the whole point of using Mockito - you can write unit tests for individual methods, without the behaviour of other methods affecting the tests.

That means you need to specify what will be returned by these two calls. This is "stubbing" the calls, and you can only do it if the objects on which the methods are being called are either spies or mocks. So in Mockito, you might write something like

doReturn(myPerson).when(mockPersonRepository).getOne(personId);

which means that whenever mockPersonReposity.getOne(personId) is called, nothing happens. The method itself doesn't run, and Mockito just immediately returns myPerson.

That's the technique you want here. So when you add stubbing to your test, it might look something like this.

@Mock private TeamRepository mockTeamRepository; 
@Mock private PersonRepository mockPersonRepository;

@Before 
public void setUp() { 
    MockitoAnnotations.initMocks(this); 
    mapper = new ModelMapper(); 
    teamService = new TeamService(mockTeamRepository, mapper); 
    personService = new PersonService(mockPersonRepository, mapper);
}

@Test
public void shouldAddPersonToTeam(){
    Team team = new Team(1L, "TestCase1", "Description1", "Krakow", 12);
    Person person = new Person(1L, "jan", "mucha", "krakow", "email1@onet.com", "Programing", "Developer");

    doReturn(team).when(mockTeamRepository).getOne(1L);
    doReturn(person).when(mockPersonRepository).getOne(1L);

    teamService.createTeam(mapper.map(team, TeamDto.class));
    personService.addPerson(mapper.map(person, PersonDto.class));

    teamService.addPersonsToTeams(team.getId(), person.getId());

    verify(mockTeamRepository).save(team);
    verify(mockPersonRepository).save(person);
}

Just a couple of extra points.

  • It's worthwhile using the prefix mock on the variable names of your mock objects, just to help keep track of which variables are mocks, and which are not.
  • It's not necessary to write times(1) in your verify calls - the default verification mode is times(1), so your code is less cluttered if you just leave it out.
  • Don't use a lower case l for a long literal - 1l looks too much like 11. For readability, always use capital L.
  • Mockito has another syntax for stubbing, that works sometimes, but not always. It looks like when(mockPersonRepository.getOne(personId)).thenReturn(person);. Many people find this more readable, but it has a whole lot of drawbacks. I recommend never using (and in fact never learning) this other syntax. My reasons for this are outlined in my answer to this question.
Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • Thanks for answere but after add Your code I have this; Argument passed to when() is null! Example of correct stubbing: doThrow(new RuntimeException()).when(mock).someMethod(); Also, if you use @Mock annotation don't miss initMocks() – Magdalena Rumakowicz Jun 07 '18 at 10:48
  • OK, are you sure you're calling `MockitoAnnotations.initMocks(this);`? Also, would either `PersonRepository` or `TeamRepository` be marked as `final`? If so, you won't be able to create mocks for them. – Dawood ibn Kareem Jun 07 '18 at 10:54
  • This can be wrong. I edit my post upper and show U my mock configuration – Magdalena Rumakowicz Jun 07 '18 at 11:09
  • Write `@Mock` in front of the declaration of the `PersonRepository`, as I showed in my answer. – Dawood ibn Kareem Jun 07 '18 at 11:12
  • Omg of course stupid mistake.but after this i have problem with create team object :/ com.softwaremind.crew.common.CreateEntityException: Creating new team - failed.There is an error with object fields – Magdalena Rumakowicz Jun 07 '18 at 11:14
  • OK, that's an entirely new problem. I'm sure you'll manage to sort this out. If you can't, it's always possible to use a mock for the `Team` as well. – Dawood ibn Kareem Jun 07 '18 at 11:16