Java引入H2 SQL数据库,使用SpringbootTest和TestRestTemplate实现开发者测试

最近项目组需要做开发者测试,了解了MockMvc和TestRestTemplate,最终选择了TestRestTemplate,具体实现如下。

1.pom依赖test相关jar包

<!-- test start-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>${spring.boot.version}</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>${h2.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
    <version>${slf4j.version}</version>
    <scope>test</scope>
</dependency>
 <!--test end-->

2. H2数据库配置,application.properties中配置

需要在scheme.sql中加入待测试类依赖的建表语句,data.sql中insert初始化数据。

spring.datasource.driverClassName=org.h2.Driver
# jdbc:h2:mem代表为内存数据库;
# uap_test为数据库名称;
# MODE=PostgreSQL代表数据库为PostgreSQL
spring.datasource.url=jdbc:h2:mem:uap_test;MODE=PostgreSQL
# 从schema.sql初始化数据库;
spring.datasource.username=
spring.datasource.password=
spring.datasource.schema=classpath:schema.sql
spring.datasource.data=classpath:data.sql
spring.h2.console.enabled=true
# mybatis-plus配置
mybatis-plus.configuration.map-underscore-to-camel-case=false

3.核心类

AbstractContextTest

该类启动Spring上下文,指定随机端口,防止冲突,使用Mockito打桩设置clusterService获取集群id默认都为1,所有用例涉及到集群id的都设为1,clusterService此为我们业务相关类,读者可自行根据自己业务场景设置打桩数据,同时还可以结合PowerMock,具体的注解可以写为:
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({“javax.management.", "javax.net.ssl.”})
@PrepareForTest({XXX.class, YYY.class})
@SpringBootTest(classes = {TestApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {TestApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class AbstractContextTest {
    @MockBean
    private ClusterService clusterService;

    /**
     * Do before
     */
    @Before
    public void doBefore() {
        ClusterEntity clusterEntity = new ClusterEntity();
        clusterEntity.setAppName("URP");
        clusterEntity.setId(1);
        Mockito.when(clusterService.queryByIdInCache(Mockito.anyInt())).thenReturn(clusterEntity);
    }
}

AbstractRest

该类使用TestRestTemplate 提供通用的exchange方法调用指定的rest请求

public abstract class AbstractRest {
    @Autowired(required = false)
    private TestRestTemplate restTemplate;

    /**
     * exchange
     *
     * @param url url
     * @param method method
     * @param restEntity restEntity
     * @param urlVariables urlVariables
     * @param <T> T
     * @return ResponseEntity
     */
    protected <T> ResponseEntity<T> exchange(
            String url, HttpMethod method, RestEntity<T> restEntity, Object... urlVariables) {
        MultiValueMap<String, String> headers = restEntity.getHeaders();
        if (headers == null) {
            headers = new LinkedMultiValueMap<>();
            headers.add("uap-app", "URP");
            headers.add("uap-cluster", "1");
            headers.add("Accept-Language", "zh-CN");
        }
        String params = restEntity.getParams()
            .entrySet()
            .stream()
            .map(entry -> entry.getKey() + "=" + entry.getValue())
            .collect(Collectors.joining("&"));

        String requestUrl = url;
        if (!StringUtils.isEmpty(params)) {
            requestUrl += "?" + params;
        }

        return this.restTemplate.exchange(requestUrl, method, new HttpEntity<>(restEntity.getBody(), headers),
            restEntity.getResponseType(), urlVariables);
    }

    /**
     * exchangeWithPageable
     *
     * @param url url
     * @param method method
     * @param restEntity restEntity
     * @param urlVariables urlVariables
     * @param <T> T
     * @return ResponseEntity
     */
    protected <T> ResponseEntity<ListPage<T>> exchangeWithPageable(
            String url, HttpMethod method, RestEntity<T> restEntity, Object... urlVariables) {
        MultiValueMap<String, String> headers = restEntity.getHeaders();
        if (headers == null) {
            headers = new LinkedMultiValueMap<>();
            headers.add("uap-app", "URP");
            headers.add("uap-cluster", "1");
            headers.add("Accept-Language", "zh-CN");
        }
        String params = restEntity.getParams()
            .entrySet()
            .stream()
            .map(entry -> entry.getKey() + "=" + entry.getValue())
            .collect(Collectors.joining("&"));

        String requestUrl = url;
        if (!StringUtils.isEmpty(params)) {
            requestUrl += "?" + params;
        }

        return this.restTemplate.exchange(requestUrl, method, new HttpEntity<>(restEntity.getBody(), headers),
            new ParameterizedTypeReference<ListPage<T>>() {}, urlVariables);
    }
}

RestEntity

用于封装请求头,请求体,请求参数,返回体

@Data
@Accessors(chain = true)
public class RestEntity<T> {
    private MultiValueMap<String, String> headers;

    private Object body;

    private Class<T> responseType;

    private Map<String, Object> params = new HashMap<>();

    /**
     * RestEntity
     *
     * @param body body
     * @param responseType responseType
     */
    public RestEntity(Object body, Class<T> responseType) {
        this.body = body;
        this.responseType = responseType;
    }

    /**
     * RestEntity
     *
     * @param responseType responseType
     */
    public RestEntity(Class<T> responseType) {
        this.responseType = responseType;
    }

    /**
     * addParam
     *
     * @param key key
     * @param value value
     * @return RestEntity
     */
    public RestEntity<T> addParam(String key, Object value) {
        this.params.put(key, value);
        return this;
    }
}

4.测试类

测试类需要继承AbstractRest 类,每个Rest增删改查请求路径定义好

@Service
public class NoteIndexRest extends AbstractRest {

    /**
     * Query note index response entity
     *
     * @param <T>        parameter
     * @param restEntity rest entity
     * @return the response entity
     */
    public <T> ResponseEntity<T> queryNoteIndex(RestEntity<T> restEntity) {
        return this.exchange("/noteindex/configs", HttpMethod.GET, restEntity);
    }

    /**
     * Add note index response entity
     *
     * @param <T>        parameter
     * @param restEntity rest entity
     * @return the response entity
     */
    public <T> ResponseEntity<T> addNoteIndex(RestEntity<T> restEntity) {
        return this.exchange("/noteindex/configs", HttpMethod.POST, restEntity);
    }

    /**
     * Modify note index response entity
     *
     * @param <T>        parameter
     * @param restEntity rest entity
     * @return the response entity
     */
    public <T> ResponseEntity<T> modifyNoteIndex(RestEntity<T> restEntity, Integer noteIndex) {
        return this.exchange("/noteindex/configs/{noteIndex}", HttpMethod.PUT, restEntity, noteIndex);
    }

    /**
     * Remove note index response entity
     *
     * @param <T>        parameter
     * @param restEntity rest entity
     * @return the response entity
     */
    public <T> ResponseEntity<T> removeNoteIndex(RestEntity<T> restEntity, String ids) {
        return this.exchange("/noteindex/configs/{noteIndex}", HttpMethod.DELETE, restEntity, ids);
    }
}

NoteIndexRestTest 继承AbstractContextTest 类,避免重复写注解和通用处理。

public class NoteIndexRestTest extends AbstractContextTest {

    @Autowired
    private NoteIndexRest noteIndexRest;

    /**
     * Add one note index
     */
    @Test
    public void should_200_when_add_one_noteIndex() {
        NoteIndexDto noteIndexDto = new NoteIndexFactory().createNoteIndexDto();
        ResponseEntity<NoteIndexDto> responseEntity = noteIndexRest.addNoteIndex(new RestEntity<>(noteIndexDto, NoteIndexDto.class));
        Assert.assertSame(HttpStatus.OK, responseEntity.getStatusCode());
        noteIndexRest.removeNoteIndex(new RestEntity<>(Object.class), String.valueOf(noteIndexDto.getNoteIndex()));
    }

    /**
     * Query all note index by cluster id
     */
    @Test
    public void should_200_when_query_all_noteIndex_by_clusterId() {
        NoteIndexDto noteIndexDto = new NoteIndexFactory().createNoteIndexDto();
        noteIndexRest.addNoteIndex(new RestEntity<>(noteIndexDto, NoteIndexDto.class));
        Assert.assertNotNull(noteIndexRest.queryNoteIndex(new RestEntity<>(DtoResponse.class)).getBody());
        noteIndexRest.removeNoteIndex(new RestEntity<>(Object.class), String.valueOf(noteIndexDto.getNoteIndex()));
    }

    /**
     * Remove one note index
     */
    @Test
    public void should_200_when_remove_one_noteIndex() {
        NoteIndexDto noteIndexDto = new NoteIndexFactory().createNoteIndexDto();
        noteIndexRest.addNoteIndex(new RestEntity<>(noteIndexDto, NoteIndexDto.class));
        ResponseEntity<Object> responseEntity = noteIndexRest.removeNoteIndex(new RestEntity<>(Object.class), String.valueOf(noteIndexDto.getNoteIndex()));
        Assert.assertSame(HttpStatus.OK, responseEntity.getStatusCode());
    }

    /**
     * Modify one note index
     */
    @Test
    public void should_200_when_modify_one_noteIndex() {
        NoteIndexDto noteIndexDto = new NoteIndexFactory().createNoteIndexDto();
        noteIndexRest.addNoteIndex(new RestEntity<>(noteIndexDto, NoteIndexDto.class));
        noteIndexDto = new NoteIndexFactory().createUpdateNoteIndexDto();
        ResponseEntity<NoteIndexDto> responseEntity = noteIndexRest.modifyNoteIndex(new RestEntity<>(noteIndexDto, NoteIndexDto.class), noteIndexDto.getNoteIndex());
        Assert.assertSame(HttpStatus.OK, responseEntity.getStatusCode());
        noteIndexRest.removeNoteIndex(new RestEntity<>(Object.class), String.valueOf(noteIndexDto.getNoteIndex()));
    }
}

NoteIndexFactory 用于生成各种Dto,通过RestEntity封装传递给Rest接口。

public class NoteIndexFactory {

    /**
     * Create note index dto note index dto
     *
     * @return the note index dto
     */
    public NoteIndexDto createNoteIndexDto() {
        NoteIndexDto noteIndexDto = new NoteIndexDto();
        noteIndexDto.setClusterId(-1);
        noteIndexDto.setAppName("UAP");
        noteIndexDto.setClusterName("URP");
        noteIndexDto.setNoteIndex(1);
        noteIndexDto.setNote1(1);
        noteIndexDto.setNote2(255);
        noteIndexDto.setNote3(255);
        noteIndexDto.setNote4(255);
        noteIndexDto.setNote5(255);
        noteIndexDto.setNote6(255);
        noteIndexDto.setNote7(255);
        noteIndexDto.setNote8(255);
        noteIndexDto.setNoteNum(1);
        return noteIndexDto;
    }

    /**
     * Create update note index dto note index dto
     *
     * @return the note index dto
     */
    public NoteIndexDto createUpdateNoteIndexDto() {
        NoteIndexDto noteIndexDto = this.createNoteIndexDto();
        noteIndexDto.setNoteNum(2);
        noteIndexDto.setNote2(2);
        return noteIndexDto;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值