《Java单元测试实战》——案例集锦:Java单元测试典型案例集锦(3)

简介: 《Java单元测试实战》——案例集锦:Java单元测试典型案例集锦(3)

《Java单元测试实战》——案例集锦:Java单元测试典型案例集锦(2) https://developer.aliyun.com/article/1232057?groupCode=java



三、 如何测试虚基类和子类


在这次单元测试比赛中,很多选手都编写了虚基类,但是没有看到任何一个选手针对虚基类进行了单独的测试。

 

1. 案例代码

 

这里,以Diamond属性配置加载为例说明。

 

1) 虚基类定义

 

首先,定义一个通用的虚基类,定义了需要子类实现的虚方法,实现了通用的配置解析方法。

 

/**
 * 虚属性回调类
 *
 * @param <T> 配置类型
 */
@Slf4j
public abstract class AbstractPropertiesCallback<T> implements DiamondDataCallback {
    /** 注入依赖对象 */
    /** 环境 */
    @Autowired
    private Environment environment;
    /** 转化服务 */
    @Autowired
    private ConversionService conversionService;
    /**
     * 接收到数据
     *
     * @param data 配置数据
     */
    @Override
    public void received(String data) {
        // 获取配置参数
        String configName = getConfigName();
        Assert.notNull(configName, "配置名称不能为空");
        T configInstance = getConfigInstance();
        Assert.notNull(configInstance, "配置实例不能为空");
        // 解析配置数据
        try {
            log.info("绑定属性配置文件开始: configName={}", configName);
            Properties properties = new Properties();
            byte[] bytes = Optional.ofNullable(data.getBytes()).orElseGet(() -> new byte[0]);
            InputStream inputStream = new ByteArrayInputStream(bytes);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            properties.load(bufferedReader);
            Bindable<T> bindable = Bindable.ofInstance(configInstance);
            Binder binder = new Binder(ConfigurationPropertySources.from(
                new PropertiesPropertySource(configName, properties)),
                new PropertySourcesPlaceholdersResolver(environment), conversionService);
            BindResult<T> result = binder.bind(configName, bindable);
            if (!result.isBound()) {
                log.error("绑定属性配置文件失败: configName={}", configName);
                return;
            }
            log.info("绑定属性配置文件成功: configName={}, configInstance={}", configName, JSON.toJSONString(configInstance));
        } catch (IOException | RuntimeException e) {
            log.error("绑定属性配置文件异常: configName={}", configName, e);
        }
    }
    /**
     * 获取配置名称
     *
     * @return 配置名称
     */
    @NonNull
    protected abstract String getConfigName();
    /**
     * 获取配置实例
     *
     * @return 配置实例
     */
    @NonNull
    protected abstract T getConfigInstance();
}

2) 子类实现

 

其次,定义了具体配置的子类,简单地实现了基类定义的虚方法。


image.png

2. 方法1:联合测试法(不推荐)

 

最简单的测试方法,就是通过子类对虚基类进行联合测试,这样同时把子类和虚基类都测试了。


/**
 * 例子配置回调测试类
 */
@RunWith(MockitoJUnitRunner.class)
public class ExampleConfigCallbackTest {
    /** 定义静态常量 */
    /** 资源路径 */
    private static final String RESOURCE_PATH = "testExampleConfigCallback/";
    /** 模拟依赖对象 */
    /** 配置环境 */
    @Mock
    private ConfigurableEnvironment environment;
    /** 转化服务 */
    @Mock
    private ConversionService conversionService;
    /** 定义测试对象 */
    /** BOSS取消费配置回调 */
    @InjectMocks
    private ExampleConfigCallback exampleConfigCallback;
    /**
     * 测试: 接收-正常
     */
    @Test
    public void testReceivedWithNormal() {
        // 模拟依赖对象
        ExampleConfig exampleConfig = new ExampleConfig();
        Whitebox.setInternalState(exampleConfigCallback, "exampleConfig", exampleConfig);
        // 调用测试方法
        String text = ResourceHelper.getResourceAsString(getClass(), RESOURCE_PATH + "exampleConfig.properties");
        exampleConfigCallback.received(text);
        // 验证依赖对象
        text = ResourceHelper.getResourceAsString(getClass(), RESOURCE_PATH + "exampleConfig.json");
        Assert.assertEquals("取消费用配置不一致", text, JSON.toJSONString(exampleConfig, SerializerFeature.MapSortField));
    }
}

3. 方法2:独立测试法(推荐)

 

其实,更好的方法是对虚基类和子类独立单元测试。

 

1) 基类测试

 

虚基类的单元测试,专注于虚基类的通用配置解析。


/**
 * 虚属性回调测试类
 */
@RunWith(MockitoJUnitRunner.class)
public class AbstractPropertiesCallbackTest {
    /** 静态常量相关 */
    /** 资源目录 */
    private static final String RESOURCE_PATH = "testAbstractPropertiesCallback/";
    /** 模拟依赖对象 */
    /** 环境 */
    @Mock
    private ConfigurableEnvironment environment;
    /** 转化服务 */
    @Mock
    private ConversionService conversionService;
    /** 定义测试对象 */
    /** 虚属性回调 */
    @InjectMocks
    private AbstractPropertiesCallback<ExampleConfig> propertiesCallback =
        CastUtils.cast(Mockito.spy(AbstractPropertiesCallback.class));
    /**
     * 测试: 接收到-正常
     */
    @Test
    public void testReceivedWithNormal() {
        // 模拟依赖方法
        // 模拟依赖方法: propertiesCallback.getConfigName
        String configName = "example";
        Mockito.doReturn(configName).when(propertiesCallback).getConfigName();
        // 模拟依赖方法: propertiesCallback.getConfigInstance
        ExampleConfig configInstance = new ExampleConfig();
        Mockito.doReturn(configInstance).when(propertiesCallback).getConfigInstance();
        // 调用测试方法
        String text1 = ResourceHelper.getResourceAsString(getClass(), RESOURCE_PATH + "exampleConfig.properties");
        propertiesCallback.received(text1);
        String text2 = ResourceHelper.getResourceAsString(getClass(), RESOURCE_PATH + "exampleConfig.json");
        Assert.assertEquals("任务配置不一致", text2, JSON.toJSONString(configInstance));
        // 验证依赖方法
        // 验证依赖方法: propertiesCallback.received
        Mockito.verify(propertiesCallback).received(text1);
        // 验证依赖方法: propertiesCallback.getConfigName
        Mockito.verify(propertiesCallback).getConfigName();
        // 验证依赖方法: propertiesCallback.getConfigInstance
        Mockito.verify(propertiesCallback).getConfigInstance();
    }
}

2) 子类测试

 

子类的单元测试,专注于对虚基类定义虚方法的实现,避免了每个子类都要针对虚基类的通用配置解析进行测试。

 

image.png



《Java单元测试实战》——案例集锦:Java单元测试典型案例集锦(4) https://developer.aliyun.com/article/1232055?groupCode=java

相关文章
|
3天前
|
安全 数据可视化 前端开发
【测试开发】用例篇 · 熟悉黑盒测试用例设计方法(2)· 正交表 · 场景设计 · 常见案例练习
【测试开发】用例篇 · 熟悉黑盒测试用例设计方法(2)· 正交表 · 场景设计 · 常见案例练习
14 0
|
3天前
|
Java
PTA帅到没朋友(Java语言)+测试点
PTA帅到没朋友(Java语言)+测试点
11 1
|
1天前
|
JavaScript Java 测试技术
《手把手教你》系列技巧篇(四十六)-java+ selenium自动化测试-web页面定位toast-下篇(详解教程)
【5月更文挑战第10天】本文介绍了使用Java和Selenium进行Web自动化测试的实践,以安居客网站为例。最后,提到了在浏览器开发者工具中调试和观察页面元素的方法。
11 2
|
2天前
|
Web App开发 JavaScript 测试技术
《手把手教你》系列技巧篇(四十五)-java+ selenium自动化测试-web页面定位toast-上篇(详解教程)
【5月更文挑战第9天】本文介绍了在Appium中处理App自动化测试中遇到的Toast元素定位的方法。Toast在Web UI测试中也常见,通常作为轻量级反馈短暂显示。文章提供了两种定位Toast元素的技巧.
10 0
|
2天前
|
Java 测试技术
Java一分钟之-单元测试:JUnit与TestNG
【5月更文挑战第16天】本文介绍了Java常用的单元测试框架JUnit和TestNG,JUnit以其简洁注解受到青睐,而TestNG则提供更高级功能如参数化测试。常见问题包括测试未执行、断言失败等,解决办法包括检查项目配置、调整测试顺序。注意保持测试简单独立,确保高覆盖率。选择合适的框架可提升代码质量。
9 0
|
3天前
|
IDE Java 测试技术
Java测试三两事
Java测试三两事
10 1
|
3天前
|
Web App开发 缓存 前端开发
《手把手教你》系列技巧篇(四十四)-java+ selenium自动化测试-处理https 安全问题或者非信任站点-下篇(详解教程)
【5月更文挑战第8天】这篇文档介绍了如何在IE、Chrome和Firefox浏览器中处理不信任证书的问题。作者北京-宏哥分享了如何通过编程方式跳过浏览器的证书警告,直接访问不受信任的HTTPS网站。文章分为几个部分,首先简要介绍了问题背景,然后详细讲解了在Chrome浏览器中的两种方法,包括代码设计和运行效果,并给出了其他浏览器的相关信息和参考资料。最后,作者总结了处理此类问题的一些通用技巧。
16 2
|
3天前
|
前端开发 测试技术 数据安全/隐私保护
软件测试 —— 案例系统缺陷报告
软件测试 —— 案例系统缺陷报告
8 1
|
3天前
|
Web App开发 JavaScript 前端开发
《手把手教你》系列技巧篇(四十三)-java+ selenium自动化测试-处理https 安全问题或者非信任站点-上篇(详解教程)
【5月更文挑战第7天】本文介绍了如何在Java+Selenium自动化测试中处理浏览器对不信任证书的处理方法,特别是针对IE、Chrome和Firefox浏览器。在某些情况下,访问HTTPS网站时会遇到证书不可信的警告,但可以通过编程方式跳过这些警告。
13 1
|
3天前
|
前端开发 Java 测试技术
《手把手教你》系列技巧篇(四十二)-java+ selenium自动化测试 - 处理iframe -下篇(详解教程)
【5月更文挑战第6天】本文介绍了如何使用Selenium处理含有iframe的网页。作者首先解释了iframe是什么,即HTML中的一个框架,用于在一个页面中嵌入另一个页面。接着,通过一个实战例子展示了在QQ邮箱登录页面中,由于输入框存在于iframe内,导致直接定位元素失败。作者提供了三种方法来处理这种情况:1)通过id或name属性切换到iframe;2)使用webElement对象切换;3)通过索引切换。最后,给出了相应的Java代码示例,并提醒读者根据iframe的实际情况选择合适的方法进行切换和元素定位。
11 0