提问者:小点点

带有spring上下文的测试方法mockito


您好,我有一个将人员添加到团队的方法。我想为此方法编写一个测试,但我是junit/mockito测试的新手,所以我有很多问题:这是我的添加方法:

@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();
    }

}

这两个实体(人员/团队)之间存在关系,这是我的测试代码,但它不起作用:

@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);


    }

模拟组合:

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个答案

匿名用户

你的问题是台词

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

在您正在测试的方法中。在addPersonsToTeams的单元测试中,您不想测试两个getOne方法的行为。这就是使用Mockito的全部意义所在——您可以为单个方法编写单元测试,而不需要其他方法的行为影响测试。

这意味着您需要指定这两个调用将返回什么。这是“存根”调用,只有在调用方法的对象是spies或mock时,才能执行此操作。所以在Mockito中,你可以写

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

这意味着每当调用mockPERReposity.getOne(man Id)时,什么都不会发生。该方法本身不会运行,Mockito只是立即返回myPerson

这就是你想要的技巧。因此,当您在测试中添加存根时,可能会出现如下情况。

@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);
}

只需多加几分。

  • 在模拟对象的变量名称上使用前缀mock是值得的,这只是为了帮助跟踪哪些变量是模拟的,哪些不是
  • 无需在验证调用中写入次(1)——默认验证模式为次(1),因此,如果不使用它,代码就不会太混乱
  • 不要使用小写字母l来表示长文字,因为l看起来太像11。为了便于阅读,请始终使用大写字母L
  • Mockito还有另一种用于存根的语法,这种语法有时有效,但并不总是有效。它看起来像是when(mockPersonRepository.getOne(personId))。然后返回(人)。许多人觉得这更具可读性,但它有很多缺点。我建议不要使用(事实上也不要学习)这种其他语法。我对这个问题的回答概述了我这样做的原因