Java 在MVC中测试外观|断言返回类型

Java 在MVC中测试外观|断言返回类型,java,testing,junit,mockito,facade,Java,Testing,Junit,Mockito,Facade,所以在MVC项目中,我有Facades,它使用服务获取信息 因此,我希望通过测试确保调用了获取信息的正确服务方法,并且我希望检查facade方法的返回类型是否符合我的预期 当然,当我需要一个用户列表时,例如,我可以模拟一个,然后使用when().thenReturn()返回列表并断言输出是相同的 问题是,我觉得嘲笑一切都很烦人。下面是Facade中的方法示例: public List<UserData> getUsersByRegion(final RegionModel userR

所以在MVC项目中,我有Facades,它使用服务获取信息

因此,我希望通过测试确保调用了获取信息的正确服务方法,并且我希望检查facade方法的返回类型是否符合我的预期

当然,当我需要一个用户列表时,例如,我可以模拟一个,然后使用when().thenReturn()返回列表并断言输出是相同的

问题是,我觉得嘲笑一切都很烦人。下面是Facade中的方法示例:

public List<UserData> getUsersByRegion(final RegionModel userRegion)
    {
        final List<UserModel> userModels = userService.getUsersByRegion(userRegion);
        final List<UserData> userFacadeData = new ArrayList<UserData>();

        for (final userModel model : userModels)
        {
            final UserData userData = new UserData(model.getEmail());
            userFacadeData.add(userData);
        }
        return userFacadeData;
    }
公共列表getUsersByRegion(最终区域Model userRegion)
{
最终列表userModels=userService.getUsersByRegion(userRegion);
最终列表userFacadeData=newarraylist();
用于(最终用户模型:用户模型)
{
final UserData UserData=newuserdata(model.getEmail());
添加(userData);
}
返回userFacadeData;
}
我是测试新手,到目前为止我所了解的是,您在不知道实现的情况下测试某些东西。所以作为一个测试人员,我不知道这个人是如何做到的,我只知道他需要使用Userservice,而我需要一个包含UserData的列表。所以我不知道,他使用model.getEmail()调用构造函数UserData()

另外,例如,我不需要测试UserService,因为我会为此编写一个额外的测试

因此,如果我现在想真正测试该方法对所有数据的处理效果,我需要模拟UserModels、UserData、RegionModels,以生成asssertEquals并使用when().thenReturn()

问题是,这是一个很短的方法。因为外观是用来抽象获取和转换信息的复杂性的,所以你有很多事情要做。所以当我有更大的方法时,我会有很多东西要嘲笑

那么这真的有必要吗?有什么我没有考虑的吗?或者我该怎么做?如果我模仿,那么对UserService使用when().thenReturn()而不是让UserService本身返回,因为可能会发生,UserService可能有bug,这难道不是明智的做法吗

注意:在JUnit/Mockito中,测试方法返回类型的方法是什么


谢谢

我认为你在嘲笑比你实际需要的更多的东西。对于示例方法,您只需要模拟
userService
实例。至于返回类型检查,我认为您不应该真正测试它,因为Java是一种类型安全的语言。如果您碰巧返回了一个与预期不同的类型,那么肯定会得到一个异常——很可能是在编译期间。示例方法的测试应如下所示:

@Test
public void testGetUsersByRegion() {
    final UserModel userModel = new UserModel(); // initialise this with all the data you need
    final List<UserModel> userModels = Collections.singletonList(userModel);
    final UserService userService = mock(UserService.class);

    doReturn(userModels).when(userService).getUsersByRegion(any(RegionModel.class));

    final UserData userData = new UserData(userModel.getEmail());
    final List<UserData> expectedResult = Collections.singletonList(userData);

    // this assumes you have an instance of your facade and you have injected the mock user service to it
    final List<UserData> actualResult = usersFacade.getUsersByRegion(testRegion);

    verify(userService).getUsersByRegion(eq(testRegion));
    assertEquals(expectedResult, actualResult);
}
@测试
public void testGetUsersByRegion(){
final UserModel UserModel=new UserModel();//使用所需的所有数据初始化此文件
最终列表userModels=Collections.singletonList(userModel);
最终用户服务UserService=mock(UserService.class);
doReturn(userModels.when(userService.getUsersByRegion)(any(RegionModel.class));
final UserData UserData=newuserdata(userModel.getEmail());
最终列表expectedResult=Collections.singletonList(userData);
//这假设您有一个facade实例,并且您已经向它注入了模拟用户服务
最终列表actualResult=usersFacade.getUsersByRegion(testRegion);
验证(userService).getUsersByRegion(eq(testRegion));
资产质量(预期结果、实际结果);
}

谢谢!这真的很有帮助。但是,当我有多个getUserMethods时,比如我不需要一个区域,或者可能我需要另一个字段?将UserModel等的创建封装在额外的build()方法中的最佳方法是什么,这样我就不必在每个方法的每个测试中实例化所有变量了?这并没有秘诀-您需要找到最适合您的情况和体系结构的方法。您可以在测试类中有工厂方法,您可以有一个集中工厂,可以根据需要创建自定义实例,您可以公开对模型类具有有限访问权限的构造函数。。。这些是我见过的和使用过的一些方法,都有优点和缺点。但我刚才注意到的是,当您调用usersFacade.getUsersByRegion(testRegion)时,您在哪里初始化了testRegion?或者,既然您声明了any(RegionModel.class),我就可以执行RegionModel testregion=newregionmodel();让它空白?是的。示例中省略了testRegion的初始化。在这种特殊情况下,我认为只需使用默认构造函数就可以了。