用MockMvc和Mockito测试Katharsis JsonApi

时间:2016-02-02 16:50:20

标签: unit-testing mockito spring-test-mvc katharsis

我想测试我的Katharsis ResourceRepository(katharsis-spring 2.1.7)配置的行为:

import io.katharsis.queryParams.QueryParams;
import io.katharsis.repository.ResourceRepository;
import org.springframework.stereotype.Component;

@Component
public class UserResourceRepository implements ResourceRepository<UserDTO, String> {

    @Autowired
    private UserRepository databaseRepository;

    @Override
    public UserDTO findOne(String email, QueryParams queryParams) {
        return null;
    }

    @Override
    public Iterable<UserDTO> findAll(QueryParams queryParams) {
        return null;
    }

    @Override
    public Iterable<UserDTO> findAll(Iterable<String> iterable, QueryParams queryParams) {
        return null;
    }

    @Override
    public void delete(String email) {
    }

    @Override
    public UserDTO save(UserDTO s) {
        return null;
    }
}

我想用与普通Spring控制器类似的方式测试它,使用Mockito模拟数据库存储库并使用MockMvc:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import java.util.Optional;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(MockitoJUnitRunner.class)
public class UserJsonApiTest {

    @InjectMocks
    private UserResourceRepository resourceRepository;

    @Mock
    private UserRepository databaseRepository;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(resourceRepository).build();
    }

    @Test
    public void first() throws Exception {
        Optional<UserEntity> user = Optional.of(new UserEntity().
                id(1).
                email("test@test").
                firstName("test first name").
                lastName("test last name").
                pass("test pass"));

        when(
                databaseRepository.
                        findOneByEmail(user.get().getEmail())).
                thenReturn(user);

        mockMvc.perform(
                get("/users/" + user.get().email())).
                andExpect(status().isOk())
        ;
    }

}

显然,这段代码不起作用,因为我的Katharsis UserResourceRepository实际上并不是一个控制器。到目前为止,我已经(从日志中)了解到它实际上使用了一些过滤器映射和名为io.katharsis.spring的类。 KatharsisFilterV2

有没有办法使用MockMvc进行此类测试?如果没有 - 有没有其他方法我可以测试它而无需启动整个服务器(使用模拟)?

1 个答案:

答案 0 :(得分:2)

你可以使用嵌入式服务器 - 比如UndertowJaxrsServer - 并注入KatharsisFeature:

  1. 创建一个扩展Application public static class MyApp extends Application {的类(MyApp)并将其部署到嵌入式服务器server.deploy(MyApp.class);
  2. 在此类中,覆盖getClasses并添加第二个类(KatharsisFeatureTest),它实现了功能KatharsisFeatureTest implements Feature
  3. 在KatharsisFeatureTest中,您可以注册KatharsisFeature,然后您可以覆盖JsonServiceLocator并注入模拟。
  4. 听起来有点复杂,但有点像魅力:) 看看我的实现。

    @RunWith(MockitoJUnitRunner.class)
    public class EndpointResourceTest {
        @Mock
        private EndpointService endpointService;
    
        @InjectMocks
        private final static EndpointResourceV1 endpointRessource = new EndpointResourceV1();
    
        private static UndertowJaxrsServer server;
    
        @BeforeClass
        public static void beforeClass() throws Exception {
            server = new UndertowJaxrsServer();
            server.deploy(MyApp.class);
            server.start();
        }
    
    
        @Test
        public void testGetEndpoint() throws URISyntaxException {
            Mockito.when(endpointService.getEndpoint("SUBMIT")).thenReturn(new EndpointDTO("SUBMIT", "a", "b"));
    
            Client client = ClientBuilder.newClient();
            Response response = client.target(TestPortProvider.generateURL("/api/endpoints/SUBMIT"))
                    .request(JsonApiMediaType.APPLICATION_JSON_API)
                    .get();
    
            Assert.assertEquals(200, response.getStatus());
            String json = response.readEntity(String.class);
            Assert.assertTrue(json.contains("SUBMIT"));
            Assert.assertTrue(json.contains("a"));
            Assert.assertTrue(json.contains("b"));
            Mockito.verify(endpointService, Mockito.times(1)).getEndpoint("SUBMIT");
        }
    
        @AfterClass
        public static void afterClass() throws Exception {
            server.stop();
        }
    
        @ApplicationPath("/api")
        public static class MyApp extends Application {
            @Override
            public Set<Class<?>> getClasses() {
                HashSet<Class<?>> classes = new HashSet<Class<?>>();
                classes.add(KatharsisFeatureTest.class);
                return classes;
            }
        }
    
        public static class KatharsisFeatureTest implements Feature {
            @Override
            public boolean configure(FeatureContext featureContext) {
                featureContext
                    .property(KatharsisProperties.RESOURCE_SEARCH_PACKAGE, "...")
                    .register(new io.katharsis.rs.KatharsisFeature(
                        new ObjectMapper(), new QueryParamsBuilder(new DefaultQueryParamsParser()), new SampleJsonServiceLocator() {
    
                            @Override
                            public <T> T getInstance(Class<T> clazz) {
                                try {
                                    if (clazz.equals(EndpointResourceV1.class)) {
                                        return (T) endpointRessource;
                                    }
    
                                    return clazz.newInstance();
                                }
                                catch (InstantiationException | IllegalAccessException e) {
                                    throw new RuntimeException(e);
                                }
                            }
    
                        }));
    
                return true;
            }
        }
    
    }