我开始使用Spring
和Mockito
。
我使用JUnit
,Mockito
,Spring boot
。
我测试了控制器,并尝试使其工作。
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = CommonConfiguration.class)
@ActiveProfiles(profiles = "embedded")
public class UserController_IntegrationWContainer_Tests {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@MockBean(name = "SignatureValidator")
private SignatureValidator signatureValidator;
private ObjectMapper objectMapper;
...
@Before
public void before() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).dispatchOptions(true).build();
this.objectMapper = new ObjectMapper();
}
@Test
public void createConfirmation() throws Exception {
...
ConfirmationDetails signature = new ConfirmationDetails("signature");
when(this.signatureValidator.validateAndEnforceSignature(signature))
.thenReturn("advanced");
mockMvc.perform(post("/distributions/1/receive")
.content(this.objectMapper.writeValueAsBytes(signature))
.contentType(MediaType.APPLICATION_JSON)
.andExpect(status().is(201));
}
此测试类用于测试UserController
。
@RestController
@Validated
@Transactional
public class UserController {
private final static Logger logger = LoggerFactory.getLogger(UserController.class);
private UserService userService;
private SignatureValidator signatureValidator;
...
@Autowired
public UserController(UserService userService, SignatureValidator signatureValidator, ...) {
this.userService = userService;
this.signatureValidator = signatureValidator;
...
}
@RequestMapping(
value = "/distributions/{distributionId}/receive",
method = RequestMethod.POST,
produces = "application/json")
public ResponseEntity<Object> confirmReceipt(
@RequestBody ConfirmationDetails signature,
@Context HttpServletRequest request,
@Digits(fraction = 0, integer = 19, message = "ID cannot exceed 19 digits")
@Min(value = 1, message = "ID must be > 0")
@PathVariable("distributionId") Long distributionId) {
logger.info("Processing request confirmReceipt");
/*for this string I want to use stub. but stub doesn't work*/
String advancedSignature = signatureValidator.validateAndEnforceSignature(signature);
...
Map<String, String> resultsMap = new HashMap<>();
resultsMap.put("code", "RECEIPT_SIGNED");
resultsMap.put("message", "Distribution download confirmed");
return new ResponseEntity<>(resultsMap, HttpStatus.CREATED);
}
}
SignatureValidator界面:
public interface SignatureValidator {
@SuppressWarnings("unchecked")
String validateAndEnforceSignature(ConfirmationDetails signature);
}
SignatureValidator的两个实现:
@Component
public class SignatureValidatorIml extends WebServiceGatewaySupport implements SignatureValidator {
...
}
@Component
public class SignatureValidatorJinn extends WebServiceGatewaySupport implements SignatureValidator {
...
}
Spring决定使用JinnServerConfiguration注入bean的实现:
@Configuration
public class JinnServerConfiguration {
final Environment env;
@Autowired
public JinnServerConfiguration(Environment env) {
this.env = env;
}
@Bean
public Jaxb2Marshaller marshaller() {
...
return marshaller;
}
@Bean
public HttpComponentsMessageSender messageSender() {
...
return messageSender;
}
@Bean
@Profile("!local")
public SignatureValidator signatureValidator(Jaxb2Marshaller marshaller,
HttpComponentsMessageSender messageSender) {
SignatureValidatorJinn signatureValidatorJinn = new SignatureValidatorJinn(env);
signatureValidatorJinn.setDefaultUri("http://.../SignatureValidationService");
signatureValidatorJinn.setMarshaller(marshaller);
signatureValidatorJinn.setUnmarshaller(marshaller);
signatureValidatorJinn.setMessageSender(messageSender);
return signatureValidatorJinn;
}
@Bean
@Profile("local")
public SignatureValidator signatureValidatorLocal(){
return new SignatureValidatorIml();
}
}
对于UserController中的所有服务,模拟工作正常。
但是,当我想模仿SignatureValidator
时,它不起作用。
在调试模式中,我看到,在测试中它使用了模拟bean,但是然后UserController运行它使用Spring bean(SignatureValidatorJinn
)而不是模拟bean。
为什么使用SignatureValidatorJinn?我认为是因为测试类有注释:@ActiveProfiles(profiles =“embedded”)。根据JinnServerConfiguration“@Profile(”!local“)”spring做出了这个决定。
此测试工作正常,直到注释@Component
已添加到SignatureValidatorIml
班级和SignatureValidatorJinn
班级。
我无法理解,为什么它使用了Spring bean。因为其他服务模拟工作正常。我发现了很多关于mock的信息,但找不到解决这个问题的方法。
我尝试做下一件事,但他们没有帮助:
修改
如果我在SignatureValidatorJinn和SignatureValidatorIml中删除@Component注释,它会很好用。但我不明白为什么会这样。
例如,使用“@Service”注释的UserService类。它成功地嘲笑了。
所以,也许有人可以解释一下,为什么“@Component”在这种情况下不允许创建模拟对象?
EDIT2
问题已解决
我无法删除注释组件,因为没有这个注释,我的应用程序中的DI将无法正常工作。 我找到了决定。 Bean称为signatureValidator。我使用名称SignatureValidator来指定bean来模拟。 那是错误的)所以跟随构造它工作正常:
@MockBean(name = "signatureValidator")
private SignatureValidator signatureValidator;
感谢大家的回复:)
答案 0 :(得分:0)
你试图模仿SignatureValidator
bean。但是你有两个bean SignatureValidatorJinn
和SignatureValidatorIml
。你的控制器使用两个bean。
尝试模拟SignatureValidatorJinn和SignatureValidatorIml之一。
@MockBean(name = "SignatureValidatorJinn")
private SignatureValidator signatureValidatorJinn;
或
@MockBean(name = "SignatureValidatorIml")
private SignatureValidator signatureValidatorIml;
用于post("/distributions/1/receive")
请求。
答案 1 :(得分:0)
你不能打电话
MockitoAnnotations.initMocks(this);
因为SpringRunner
已经初始化了模拟。通过调用initMocks
,您可以为signatureValidator
分配一个新对象。所有Mockito操作(例如when
和verify
)都在新对象上执行,但Spring仍然使用由SignatureValidator
创建的“旧”SpringRunner
。