用Mockito测试

时间:2015-01-07 00:12:38

标签: spring mocking mockito

我试图用Mockito测试一些服务,但是当我测试的主类和我注入Mocks的地方调用super时我遇到了问题。 我用spring运行项目,这是我为了得到错误而遵循的步骤。

这是我创建测试的地方

public class UrlShortenerTests {

 private MockMvc mockMvc;

 @Mock
 private ShortURLRepository shortURLRepository;

 @Mock
 private ClickRepository clickRespository;

 @InjectMocks
 private UrlShortenerControllerWithLogs urlShortenerWL;


 @Before
 public void setup() {
     MockitoAnnotations.initMocks(this);
     this.mockMvc = MockMvcBuilders.standaloneSetup(urlShortenerWL).build();
 }

 @Test
 public void thatShortenerCreatesARedirectIfTheURLisOK() throws Exception {
     mockMvc.perform(post("/link")
             .param("url", "http://www.google.com"))
             .andDo(print())
             .andExpect(status().isCreated())
             .andExpect(jsonPath("$.target", is("http://example.com/")));
 }
}

这是类UrlShortenerControllerWithLogs的方法shortener,这是我想用之前的POST调用测试的那个

@RestController
public class UrlShortenerControllerWithLogs extends UrlShortenerController {

@Autowired
private ClickRepository clickRepository;
@Autowired
private ShortURLRepository SURLR;

public ResponseEntity<ShortURL> shortener(@RequestParam("url") String url,
        @RequestParam(value = "sponsor", required = false) String sponsor,
        @RequestParam(value = "brand", required = false) String brand,
        HttpServletRequest request) {

    ResponseEntity<ShortURL> su = super.shortener(url, sponsor, brand,
            request);
    return su;
}

这是超级

@RestController
public class UrlShortenerController {

@Autowired
protected ShortURLRepository shortURLRepository;

@Autowired
protected ClickRepository clickRepository;

@RequestMapping(value = "/link", method = RequestMethod.POST)
public ResponseEntity<ShortURL> shortener(@RequestParam("url") String url,
        @RequestParam(value = "sponsor", required = false) String sponsor,
        @RequestParam(value = "brand", required = false) String brand,
        HttpServletRequest request) {
    ShortURL su = createAndSaveIfValid(url, sponsor, brand, UUID
            .randomUUID().toString(), extractIP(request));
    if (su != null) {
        HttpHeaders h = new HttpHeaders();
        h.setLocation(su.getUri());
        return new ResponseEntity<>(su, h, HttpStatus.CREATED);
    } else {
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }
}

protected ShortURL createAndSaveIfValid(String url, String sponsor,
        String brand, String owner, String ip) {
    UrlValidator urlValidator = new UrlValidator(new String[] { "http",
            "https" });
    if (urlValidator.isValid(url)) {
        String id = Hashing.murmur3_32()
                .hashString(url, StandardCharsets.UTF_8).toString();
        ShortURL su = new ShortURL(id, url,
                linkTo(
                        methodOn(UrlShortenerController.class).redirectTo(
                                id, null)).toUri(), sponsor, new Date(
                        System.currentTimeMillis()), owner,
                HttpStatus.TEMPORARY_REDIRECT.value(), true, ip, null);
        return shortURLRepository.save(su);
    } else {
        return null;
    }
}

因此,当我在第二个方法(createAndSaveIfValid)中调用shortURLRepository.save(su)时,它从不进入方法save,因此它返回null而不是我想要的对象。

ShortURLRepository的实现代码和方法save是:

@Repository
public class ShortURLRepositoryImpl implements ShortURLRepository {

private static final Logger log = LoggerFactory
        .getLogger(ShortURLRepositoryImpl.class);
@Override
public ShortURL save(ShortURL su) {
    try {
        jdbc.update("INSERT INTO shorturl VALUES (?,?,?,?,?,?,?,?,?)",
                su.getHash(), su.getTarget(), su.getSponsor(),
                su.getCreated(), su.getOwner(), su.getMode(), su.getSafe(),
                su.getIP(), su.getCountry());
    } catch (DuplicateKeyException e) {
        log.debug("When insert for key " + su.getHash(), e);
        return su;
    } catch (Exception e) {
        log.debug("When insert", e);
        return null;
    }
    return su;
}

我认为问题在于测试类中创建的对象ShortURLRepository没有在超类(UrlShortenerController)或类似的东西上初始化。

有可能吗? 有人能帮助我吗?

完整代码位于:https://github.com/alberto-648702/UrlShortener2014

UrlShortenerTests课程位于:

bangladeshGreen/src/test/java/urlshortener2014/bangladeshgreen

UrlShortenerControllerWithLogs类位于:

bangladeshGreen/src/main/java/urlshortener2014/bangladeshgreen/web

UrlShortenerController类位于:

common/src/main/java/urlshortener2014/common/web

ShortURLRepositoryImpl类位于:

common/src/main/java/urlshortener2014/common/repository

1 个答案:

答案 0 :(得分:0)

这不是错误。这是预期的行为。 @Mock创建了一个模拟。 @InjectMocks创建类的实例并注入使用@Mock创建的模拟。模拟不是具有已知值和方法的真实对象。它是一个与声明类型具有相同接口的对象,但您可以控制其行为。默认情况下,模拟对象方法不执行任何操作(例如,返回null)。因此,如果ShortURLRepository被模拟并注入UrlShortenerControllerWithLogs注入save中的ShortURLRepository,并未按预期调用实际代码,则不执行任何操作。如果您想模仿save的行为,请在setup中添加以下代码:

when(shortURLRepository.save(org.mockito.Matchers.any(ShortURL.class))).
    then(new Answer<ShortURL>() {
        @Override
        public ShortURL answer(InvocationOnMock invocation) throws Throwable {
            ShortURL su = (ShortURL) invocation.getArguments()[0];
            // Do something with su if needed
            return su;
    }
});