Java 单元测试基础封装

pom 文件导入 jar 包依赖
<!-- 模拟数据库时使用 -->
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.200</version>
    <scope>test</scope>
</dependency>
<!-- 需要启动 redis 服务时使用 -->
<!-- https://mvnrepository.com/artifact/ai.grakn/redis-mock -->
<dependency>
    <groupId>ai.grakn</groupId>
    <artifactId>redis-mock</artifactId>
    <version>0.1.6</version>
    <scope>test</scope>
</dependency>
<!-- 需要使用 zookeeper server 时使用 -->
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-test -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-test</artifactId>
    <version>5.0.0</version>
    <scope>test</scope>
</dependency>

编写 H2 数据库工具类

工具类主要用来执行 sql 语句文件,初始化脚本请在 配置文件中配置 schema

import lombok.extern.slf4j.Slf4j;
import org.h2.tools.RunScript;

import java.io.FileReader;
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2020/6/17 17:16
 */
@Slf4j
public class H2Utils {

    private static Connection CONNECTION = null;

    static {
        try {
            // 加载驱动
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException ex) {
            log.error("get driver error", ex);
        }
    }

    private static void setupConn(String url) throws SQLException {
        if (null == CONNECTION || CONNECTION.isClosed()) {
            // 获取链接
            CONNECTION = DriverManager.getConnection(url, "admin", "admin123");
        }
    }

    private static Statement getStatement() throws SQLException {
        if (null == CONNECTION || CONNECTION.isClosed()) {
            SQLException ex = new SQLException("No valid database connection!");
            throw ex;
        }

        return CONNECTION.createStatement();
    }

    /**
     * 关闭工具类的使用
     */
    public static void close() {
        try {
            CONNECTION.close();
        } catch (SQLException throwables) {
            log.error("run script error", throwables);
        }
    }

    /**
     * 开启工具类的使用
     */
    public static void start(String db) {
        try {
            setupConn(db);
        } catch (SQLException throwables) {
            log.error("run script error", throwables);
        }
    }

    /**
     * 执行 sql 语句文件
     */
    public static void runScript(String filename) {
        String realPath = H2Utils.class.getResource(filename).getPath();
        try (Reader reader = new FileReader(realPath)) {
            RunScript.execute(CONNECTION, reader);
        } catch (Exception e) {
            log.error("run script error", e);
        }
    }

}

Spring Boot 容器模拟程序启动基类——ApplicationTests

一些需要启动整个环境的测试则需要继承该类

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2020/6/23 16:33
 */
@Slf4j
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ApplicationTests {

    // 测试完成后停止资源
    // redis 客户端,未配置则不需要
    private static LettuceConnectionFactory LETTUCE_C_C;

    @Autowired(required = false)
    private LettuceConnectionFactory lettuceConnectionFactory;

    @Autowired
    protected MockMvc mockMvc;

    static {
        ServersUtils.startRedisServer();
        H2Utils.start("jdbc:h2:mem:db_tests;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE");

        Runtime.getRuntime().addShutdownHook(new Thread("xx-shutdown-hook") {
            @Override
            public void run() {
                //资源释放动作
                destory();
            }
        });
    }

    @PostConstruct
    private void init() {
        LETTUCE_C_C = lettuceConnectionFactory;
    }

    static void destory() {
        // H2Utils stop
        H2Utils.close();

        // 销毁 Redis 客户端,主要是重连机制引发的程序无法关闭的问题
        if (LETTUCE_C_C != null)
            LETTUCE_C_C.destroy();

        ServersUtils.stopRedisServer();
    }

}
模拟服务启动工具类——ServiceUtils

一些集成服务模拟:redis,zookeeper

import ai.grakn.redismock.RedisServer;
import lombok.extern.slf4j.Slf4j;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2020/6/18 9:02
 */
@Slf4j
public class ServersUtils {

    private static RedisServer redisServer = null;

    public static void startRedisServer() {
        try {
            if (redisServer == null) {
                redisServer = RedisServer.newRedisServer();
                redisServer.start();
                log.info("start redis server: port={}", redisServer.getBindPort());
                System.setProperty("spring.redis.port", Integer.toString(redisServer.getBindPort()));
            }
        } catch (Exception e) {
            log.error("start redis server error", e);
            stopRedisServer();
        }
    }

    public static void stopRedisServer() {
        if (redisServer != null)
            redisServer.stop();
    }


    private static TestingServer zookeeperServer = null;

    public static void startZookeeperServer(Integer port) {
        try {
            if (zookeeperServer == null) {
                log.info("start zookeeper server: port={}", port);
                zookeeperServer = new TestingServer(port);
            }
        } catch (Exception e) {
            log.error("start zookeeper server error", e);
        }
    }

    public static void stopZookeeperServer() {
        try {
            if (zookeeperServer != null)
                zookeeperServer.close();
        } catch (IOException e) {
            log.error("stop zookeeper server error", e);
        }
    }

}

Controller 测试基类——BaseControllerTest

用来 mock 测试 api 接口

import com.google.gson.Gson;
import com.sdstc.OrderApplicationTests;
import com.sdstc.core.utils.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import java.util.Map;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2020/6/19 9:30
 */
public class BaseControllerTests extends ApplicationTests {

    protected ResultActions get(String path, HttpHeaders httpHeaders, Map<String, String> params) throws Exception {
        MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(path);
        if (httpHeaders != null)
            requestBuilder.headers(httpHeaders);

        if (params != null)
            params.forEach(requestBuilder::param);

        // 模拟 track_code。针对 RequestInfoForwardInterceptor 拦截引发的问题
        requestBuilder.header("track_code", StringUtils.randomIntString(12));

        return mockMvc.perform(requestBuilder);
    }

    protected ResultActions post(String path, HttpHeaders httpHeaders,
                                 Map<String, String> params,
                                 Object body) throws Exception {
        MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(path);
        if (httpHeaders != null)
            requestBuilder.headers(httpHeaders);

        if (params != null)
            params.forEach(requestBuilder::param);

        if (body != null)
            requestBuilder.content(new Gson().toJson(body));

        requestBuilder.contentType(MediaType.APPLICATION_JSON);
        // 模拟 track_code。针对 RequestInfoForwardInterceptor 拦截引发的问题
        requestBuilder.header("track_code", StringUtils.randomIntString(12));

        return mockMvc.perform(requestBuilder);
    }

}

Service 测试基类——BaseServiceTests

测试 service 时只需要测试方法逻辑的准确性,不需要启动整个容器,直接使用 mockito 测试

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2020/6/18 16:58
 */
public class BaseServiceTests {

    @BeforeEach
    void initMockito() {
        MockitoAnnotations.initMocks(this);
    }

}

Dao 测试基类——BaseMapperTests

测试 dao 需要启动 spring 容器,所以需要继承 ApplicationTests
可以在这个基类中进行一些必要的准备

public class BaseMapperTests extends ApplicationTests {

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Effective Java》是一本由Joshua Bloch所著的Java编程指南。这本书被广泛认可为提高编写高质量,高效率Java代码的标准参考。 《Effective Java》首先强调的是Java编程的基础,包括了Java编程语言的核心特性和语法规则。该书通过一系列准则和最佳实践,教会我们如何正确地使用Java中的不同特性和库函数。 该书对于Java中的各种语言特性和构建代码的技术提供了深入的解释和用例。比如,它解释了如何正确使用泛型和注解,以及如何避免常见的错误和陷阱。它还教授了如何设计和实现高效的算法和数据结构。 此外,《Effective Java》还强调了面向对象设计的原则和模式。它引导我们理解封装、继承和多态的概念,并演示了如何遵循开放封闭原则、里氏替换原则等设计原则。 这本书不仅仅教会了我们如何写出高质量的代码,还给了我们一些建筑可扩展,可维护和可重用的代码的指导原则。它教授了我们如何组织代码,如何编写可读性高的注释,以及如何进行单元测试和调试。 总而言之,《Effective Java》是一本非常实用的Java编程指南。它提供了丰富的经验和技巧,能够帮助开发人员写出更高质量,更高效率的Java代码。无论是初学者还是有经验的开发人员,都可以从这本书中受益良多,将其中的原则和技巧应用到自己的实际项目中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值