使用junit和mockito在javaee应用程序中测试带有Restapi调用的服务



我正在尝试使用JUnit和Mockito测试一个Service类。不确定如何在测试方法中包含HTTP GET请求URI。我试图使用HttpClientBuilder创建和构建请求,但不知何故,即使在我包含Gradle依赖项之后,也找不到导入。我在请求中也有Header参数。

我的Java类如下:

@GET
@Path("/home")
public Response getAllEmployees(@HeaderParam("user") String user, @HeaderParam("password") String password) {
List<Info> listOfInfo = new ArrayList<>();
LoginUser loginUser = checkLoginValidation();

if(loginUser != null){
List<Employees> list = employeeManager.fetchAllEmployees();
if(list == null || list.isEmpty()){
return Response.status(Status.NO_CONTENT).build();
}

listOfInfo = getEmployees(list);
log.info(listOfInfo);
return Response.ok(listOfInfo, MediaType.APPLICATION_JSON_TYPE).build();
}

return Response.status(Status.BAD_REQUEST).build();
}

这就是我在下面的测试课上写的全部内容:

@RunWith(MockitoJUnitRunner.class)
public class FinderServiceTest {
@InjectMocks
private FinderService finderService;
@Test
public void testMethod() {
HttpGet request = new HttpGet("http://localhost:8080/home");

//Don't know how to proceed further
}
}

任何帮助都将不胜感激!

你的问题的措辞我担心你在混合单元和集成级别的测试。

在单元级别,您希望断言当受控参数传递给方法时,您可以预测地断言该方法将执行什么并返回给客户端。这是一个隔离测试,将该方法与它将在其中执行的环境分离开来,并专注于确保代码的一小部分具有可预测的行为。

在集成级别,您可以将类视为"运行时存在的类"。你可以把它放在一个容器中,启动bean或服务,并对它进行调用,以确保当它运行时,行为是同样可预测的,外部客户端将通过你的完整运行堆栈(或受控堆栈子集(从公众那里获得你所期望的结果。集成测试是检查应用程序是否按照您的意愿共同运行。

使用您提出的测试,我感觉您正在尝试执行该方法的单元测试。我建议您不要担心在运行时如何从Header派生参数,只需直接调用该方法即可。

下面是我认为我将如何尝试对ServiceFinder.getAllLockers(String,String(方法进行单元测试的存根

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.util.reflection.Whitebox;
public class FinderServiceTest {
// This is created new between each test.
private ServiceFinder serviceFinder = new ServiceFinder();
/* ***************************************/
/*  PARAMETER TESTS
/* ***************************************/
/*
* What should happen in these cases? - Is it an Exception? - Should the method return Status.BAD_REQUEST?
* 
* org.junit.Assert can be used to compare the response Object with the desired outcome OR
* org.junit.rules.ExpectedException can be used to verify specific exceptions are thrown
*/
@Test
public void testGetAllLockersNullUserParam() {
Response response = serviceFinder.getAllLockers(null, "password");
// Assert the right thing happened.
}
@Test
public void testGetAllLockersEmptyUserParam() {
Response response = serviceFinder.getAllLockers("", "password");
// Assert the right thing happened.
}
@Test
public void testGetAllLockersNullPasswordParam() {
Response response = serviceFinder.getAllLockers("user", null);
// Assert the right thing happened.
}
@Test
public void testGetAllLockersEmptyPasswordParam() {
Response response = serviceFinder.getAllLockers("user", "");
// Assert the right thing happened.
}
/* ***************************************/
/*  BRANCH TESTS (SHORT PATHS)
/* ***************************************/
@Test
public void testGetAllLockersNullValidatedUser() {
// For ease of use in my case I'm going to pretend that checkLoginValidation 
// just calls a delegate interface, which I'm calling LoginValidator, with the same API.
// Which I will mock and set the expected return...
LoginValidator mockLoginValidator = Mockito.mock(LoginValidator.class);
Mockito.when(mockLoginValidator.checkLoginValidation()).thenReturn(null);
//Using PowerMock, I'm going to set the LoginValidator field inside of my service finder.
//I'm assuming that LoginValidator field in the ServiceFinder is named "loginValidator"
Whitebox.setInternalState(serviceFinder, "loginValidator", mockLoginValidator);
//Now that my class is set up to give me the null Validated User, I'll make the call to the test instance
Response response = serviceFinder.getAllLockers("validUser", "validPassword");
//From the implementation posted, I know that when the user validates as null I should get back something with a Status.BAD_REQUEST state.
assertEquals("When the logged in user is null BAD_REQUEST should be returned", Status.BAD_REQUEST, response.getStatus);   
}
@Test
public void testGetAllLockersNullEmployeeList() {
//FIXME:  Configure user validation to return LoginUser Object.
//FIXME:  Configure test reference state to return a null employee list when employeeManager.fetchAllEmployees() is called
Response response = serviceFinder.getAllLockers("validUser", "validPassword");
assertEquals("When the employee list is null NO_CONTENT should be returned", Status.NO_CONTENT, response.getStatus);   
}
@Test
public void testGetAllLockersEmptyEmployeeList() {
//FIXME:  Configure user validation to return LoginUser Object.
//  FIXME:  Configure test reference state to return an empty employee list when employeeManager.fetchAllEmployees() is called
Response response = serviceFinder.getAllLockers("validUser", "validPassword");
assertEquals("When the employee list is null NO_CONTENT should be returned", Status.NO_CONTENT, response.getStatus);
}
/* ***************************************/
/*  HAPPY PATH TEST
/* ***************************************/
public void testgetAllLockers() {
//FIXME:  Configure user validation to return LoginUser Object.
//  FIXME:  Configure test reference state to return a correctly-populated employee list when employeeManager.fetchAllEmployees() is called
Response response = serviceFinder.getAllLockers("validUser", "validPassword");
assertEquals("When the employee list is null NO_CONTENT should be returned", Status.OK, response.getStatus);
//FIXME get JSON from response reference
//FIXME Check that JSON holds all of the expected employee list data
}
}

在单元级别上,确保该方法重复执行我们期望的操作。


集成测试是我心目中的另一头野兽。你需要让你的代码在服务器上运行,并设置一个可以对运行中的URL进行调用的工具。这种配置我并不太熟悉,所以在这方面我没有太大帮助。我知道有很多方法可以做到这一点,还有很多程序和实用程序可以提供帮助。在谷歌上搜索一些关于集成测试rest api的内容,我相信你会有很多选择。我建议您寻找一个与您最终想要运行的环境非常相似的解决方案。

我可以提供的是,在集成测试期间,您需要使用类似HttpClientBuilder的工具,或类似JMeterPostman的工具来向服务器发送信息请求,然后读取并验证响应。您可能需要使用我们在单元测试中尝试的一些数据,以确保运行的系统不会更改预期结果。

祝你好运!

最新更新