Spring Boot Controller Test-Mockito当返回列表不工作时



我在嘲笑我的MemberServiceImpl类。特别是以下返回List<Golfer>:的getMembers()方法

@Service
public class MemberServiceImpl implements MemberService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
MemberRepository repository;
@Override
public List<Golfer> getMembers() {
List<Golfer> members = repository.findAll();
return members;
}

在我的MemberControllerTest类中,我创建了一个高尔夫球手列表,并在发送GET请求之前使用whenthenReturn(members),它总是返回一个空列表。任何想法我做错了什么:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MemberControllerTest {
@Mock
MemberService memberService;
@InjectMocks
MemberController memberController = new MemberController();
@Autowired
private TestRestTemplate restTemplate;
//bind RANDOM_PORT
@LocalServerPort
private int port;
private String name = "David";
private Golfer member = new Golfer("David");
private HttpHeaders headers = new HttpHeaders();
private String baseUrl = "http://localhost:";
@Test
void testGetAllMembers() throws Exception{
restTemplate = new TestRestTemplate();
HttpHeaders headers = new HttpHeaders();
Golfer member1 = new Golfer("Harry");
Golfer member2 = new Golfer("Maureen");
List<Golfer> members = new ArrayList<Golfer>();
members.add(member1);
members.add(member2);
when(memberService.getMembers()).thenReturn(members);
ResponseEntity<List<Golfer>> response = restTemplate.exchange("http://localhost:"+port, HttpMethod.GET, null, new ParameterizedTypeReference<List<Golfer>>() {});
assertEquals(members,response.getBody());
}   
}

您正在模拟控制器对象,但希望它能处理请求。让Spring像在正常的应用程序启动中一样创建控制器,不需要自己定义它。

但是您需要将MemberService的定义更改为@MockBean,这意味着当Spring需要一个服务将其注入到它创建的控制器中时,它将使用这个mock-bean:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MemberControllerTest {
@MockBean
MemberService memberService;
@Autowired
private TestRestTemplate restTemplate;
//bind RANDOM_PORT
@LocalServerPort
private int port;
private String name = "David";
private Golfer member = new Golfer("David");
private HttpHeaders headers = new HttpHeaders();
private String baseUrl = "http://localhost:";
@Test
void testGetAllMembers() throws Exception{
restTemplate = new TestRestTemplate();
HttpHeaders headers = new HttpHeaders();
Golfer member1 = new Golfer("Harry");
Golfer member2 = new Golfer("Maureen");
List<Golfer> members = new ArrayList<Golfer>();
members.add(member1);
members.add(member2);
when(memberService.getMembers()).thenReturn(members);
ResponseEntity<List<Golfer>> response = restTemplate.exchange("http://localhost:"+port, HttpMethod.GET, null, new ParameterizedTypeReference<List<Golfer>>() {});
assertEquals(members,response.getBody());
}
}

应用程序(测试(上下文不会拾取您的mock。因此,即使您模拟您的服务并将其注入到测试中的控制器实例中,当您对(测试(应用程序发出请求时,该控制器实例也不是应用程序上下文将使用的实例。

不要使用@Mock和@InjectMocks,而是创建一个TestConfiguration类,并为ServiceImpl使用@MockBean。将控制器一起从测试中删除,因为你不必与它交互

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 
@Import(MemberControllerTestConfiguration.class)
class MemberControllerTest {
@Autowired
MemberService memberService;
@Autowired
private TestRestTemplate restTemplate;
//rest of your test
}

@TestConfiguration
class MemberControllerTestConfiguration{
@MockBean
MemberService memberService;
}

我通常倾向于将测试配置粘贴在同一测试文件的底部,以将它们放在一起,因为这只是本次测试将使用的内容。如果被嘲笑的bean开始抱怨太多的bean ,你可能不得不用@Primary来注释它