单元测试可执行程序可调用

我有一个像这样的控制器类,它将一些执行程序传递给可运行的实例。这不是它的工作原理,但为了简单起见,我是这样做的。


package com.test.executor;


import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Controller {

    private ExecutorService executor;


    public Controller() {

        executor = Executors.newCachedThreadPool();

    }


    public void doRun() {

        MyRunner runner = new MyRunner(executor);

        Thread myRunner = new Thread(runner);

        myRunner.start();

    }


    public static void main(String[] args) {

        new Controller().doRun();

    }

}

runner 接收 executor 的实例,然后传递某些可调用对象。现在,可调用对象有点不同,因为一些可调用对象访问数据库/调用某些 Web 服务/文件系统


我在如何为这种情况编写合适的 JUnit 方面遇到了一些问题。我想拥有尽可能多的代码覆盖率。


package com.test.executor;


import java.util.Collections;

import java.util.List;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Future;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.TimeoutException;


public class MyRunner implements Runnable {


    private ExecutorService executor;


    public MyRunner(ExecutorService executor) {

        this.executor = executor;

    }


    @Override

    public void run() {

        // TODO Auto-generated method stub

        Future<Boolean> ret1 = executor.submit(new SampleCall1());


        try {

            ret1.get(5, TimeUnit.MINUTES);

        } catch (InterruptedException | ExecutionException | TimeoutException e) {

            e.printStackTrace();

        }


        // Do other things


        Future<List<String>> ret2 = executor.submit(new SampleCall2());


        try {

            ret2.get(5, TimeUnit.MINUTES);

        } catch (InterruptedException | ExecutionException | TimeoutException e) {

            e.printStackTrace();

        }


我的问题是为此编写单元测试的正确方法是什么。我正在收集一些关于如何对这门课进行单元测试的建议?我不确定在我的 junit/mockito 实例中要模拟什么。我应该嘲笑每个可调用的吗?然后为 MyRunner 创建一个测试用例。


我担心依赖性......因为我正在连接到数据库/网络服务/和文件系统,所以我想寻求一些建议。


宝慕林4294392
浏览 172回答 2
2回答

皈依舞

不要在代码覆盖率上花费太多时间。以某种方式务实。测试什么值得测试。提高您的测试质量,而不是数量。关于指标的一些旁注:100% 的线路覆盖率不如高分支覆盖率重要,获得高分支覆盖率可能会花费您很多时间,即使如此:您可能不需要采用每条可能的路线。PIT(突变测试)是一个有用的“工具”,它通过更改被测代码来检查您的测试实际上有多好。但是使用该信息作为指导,而不是作为实施更多测试的措施。不要夸张!(也许如果你正在开发一个库,你不想再经常改变,或者你想让它坚如磐石(并且你有空闲时间),你可以,否则我不会)曾经有一段时间我非常准确地测试了一切。问题:一旦发生变化(例如:今天我们需要 X,明天它是 Y),您的许多测试就会失败。然后需要大量返工。如果您测试最合适的,一旦需求发生显着变化,您就可以专注于重要的事情,这应该花费更少的时间。查看您提供的代码,我可能会为每个 -Callable实现编写一个测试(类),以确保它们执行我想要的操作(这可能会导致提取 -Callable类作为副作用)。对于控制器和跑步者,我还不太确定......MyRunner对我来说似乎已经过时了......但也许不是。所以可能我只会测试控制器......关于模拟:我开始尽可能地省略模拟。大多数时候,我还添加了集成测试,我想知道系统作为一个整体如何运作以及它是否按预期工作。我看过很多测试,其中有很多模拟,通过更改任何代码,没有单元测试失败,即使我认为有些测试应该失败。我也见过很多单元测试,单元测试实际上看起来像集成测试,但到处都是模拟。那么模拟首先有什么帮助?单独设置模拟可能花费了太多时间。但这又是我的看法。因此,尽管许多人喜欢测试金字塔有一个广泛的单元测试底部,但我认为它更务实,并将一些测试移到集成测试“层”而不是使用大量模拟。最后它'&nbsp;也是可用性和速度的问题。你希望你的测试快速给出结果,但你仍然希望结果最有价值(模拟只给出部分)。

天涯尽头无女友

编写一个巨大的MyRunnableTest测试类和编写一个巨大的MyRunnable生产类一样具有代码味道。由于您Callable的每个s 都是不同的并且访问不同的 I/O 资源,因此您希望分别测试它们中的每一个。实际的方法,例如文件系统操作的单元测试或嵌入式 H2 数据库的集成测试,应根据具体情况选择。提取Callables 应该给你一个较小的MyRunnable类。您现在可以拆分run()成更小的方法或类并分别测试它们。此时,您可以模拟ExecutorService.您应该ExecutorService在Controller创建实际对象的类的测试中测试该对象。覆盖率只是一种帮助您衡量测试质量的工具。高覆盖率本身并不是目标。如果你把它发挥到极致,你可以轻松地获得 100% 的代码覆盖率,而不是测试中的单个断言。您可以应用测试驱动开发等其他技术和PIT 变异测试等工具来改进您的测试。但是,您应该首先使您的生产代码易于测试。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java