如何清洁测试使用domainClassConverter检索参数的弹簧控制器



我对清洁良好的单元测试很重要。但是我在这里绊倒在这里的"干净"部分,用于测试一个控制器,该控制器使用DomainClassConverter功能将实体作为其映射方法的参数。

@Entity
class MyEntity {
    @Id
    private Integer id;
    // rest of properties goes here.
}

控制器的定义

@RequestMapping("/api/v1/myentities")
class MyEntitiesController {
    @Autowired
    private DoSomethingService aService;
    @PostMapping("/{id}")
    public ResponseEntity<MyEntity> update(@PathVariable("id")Optional<MyEntity> myEntity) {
        // do what is needed here
    }
}

因此,从DomainClassConverter小文档中,我知道它使用CrudRepository#findById查找实体。我想知道的是如何在测试中干净地嘲笑。通过执行此步骤,我取得了一些成功:

  1. 创建一个可以模拟的自定义转换器/格式化器
  2. 用上述转换器实例化我自己的MockMVC
  3. 在每个测试中重置模拟和更改行为。

问题在于,设置代码很复杂,因此很难进行调试和解释(我的团队是来自Rails或Uni的99%的初中生,因此我们必须保持简单(。我想知道是否有一种方法可以从我的单位测试中注入所需的MyEntity实例,同时使用@Autowired MockMvc进行测试。

目前,我正在尝试查看是否可以为MyEntity注入CrudRepository的模拟,但没有成功。我已经几年(4(尚未在春季/Java工作,因此我对可用工具的了解可能不是最新的。

因此,从" domainclassconverter"小文档中,我知道它使用crudrepository#findbyid查找实体。我想知道的是如何在测试中干净地嘲笑。

您需要模拟2种在CrudRepository#findById之前称为的方法,以返回所需的实体。下面的示例是使用RestAssuredMockMvc,但是如果您还注入WebApplicationContext,则可以使用MOCKMVC进行相同的操作。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SomeApplication.class)
public class SomeControllerTest {
    @Autowired
    private WebApplicationContext context;
    @MockBean(name = "mvcConversionService")
    private WebConversionService webConversionService;
    @Before
    public void setup() {
        RestAssuredMockMvc.webAppContextSetup(context);
        SomeEntity someEntity = new SomeEntity();
        when(webConversionService.canConvert(any(TypeDescriptor.class), any(TypeDescriptor.class)))
                .thenReturn(true);
        when(webConversionService.convert(eq("1"), any(TypeDescriptor.class), any(TypeDescriptor.class)))
                .thenReturn(someEntity);
    }
}

在某个时候,Spring Boot将执行WebConversionService::convert,稍后将调用DomainClassConverter::convert,然后将invoker.invokeFindById之类的内容使用,它将使用实体存储库查找实体。

为什么模拟WebConversionService而不是DomainClassConverter?因为DomainClassConverter是在申请启动过程中实例化的,而无需注入:

DomainClassConverter<FormattingConversionService> converter =
        new DomainClassConverter<>(conversionService);

同时,WebConversionService是一种bean,可以使我们模拟它:

@Bean
@Override
public FormattingConversionService mvcConversionService() {
    WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
    addFormatters(conversionService);
    return conversionService;
}

将模拟豆命名为mvcConversionService很重要,否则不会替换原始豆。

关于存根,您需要模拟2种方法。首先,您必须说您的模拟可以转换任何内容:

when(webConversionService.canConvert(any(TypeDescriptor.class), any(TypeDescriptor.class)))
        .thenReturn(true);

,然后是主要方法,该方法将与URL路径中定义的所需实体ID匹配:

when(webConversionService.convert(eq("1"), any(TypeDescriptor.class), any(TypeDescriptor.class)))
        .thenReturn(someEntity);

到目前为止一切都很好。但是,匹配目标类型也不会更好吗?像eq(TypeDescriptor.valueOf(SomeEntity.class))这样的东西?它会,但这会创建一个新的实例,该实例的键入标题是在域转换期间调用此存根的情况下不匹配的。

这是我使用的最干净的解决方案,但我知道,如果春季允许它会好很多。

相关内容

  • 没有找到相关文章

最新更新