来自 void 类的模拟异步调用

Posted

技术标签:

【中文标题】来自 void 类的模拟异步调用【英文标题】:Mock Asynchronous Call from void class 【发布时间】:2015-04-18 23:12:29 【问题描述】:

我有一个类,我想使用 mockito 进行测试。描述类的最好方法是粘贴代码,但我会尽量简短地做到最好。

该类有一个 void 函数并调用另一个通过 setter 和 getter 方法传入的对象。正在调用的对象(来自 void 函数)是异步调用。

我面临的问题是模拟 void 函数(通过 junit 测试)使用的异步调用。

public class Tester 

    private Auth auth; // not mock'ed or spy'ed
    @Mock private Http transport;

    @Before
    ....

    @Test
    public void testVoidFunctionFromAuth() 

        doAnswer(new Answer<Object>() 
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable 
                return doOutput();
            
        ).when(transport).executeAsync(param1, param2, param3...);

        auth.obtainAuth(); // void function that uses transport mock class
        // obtainAuth calls transport.executeAsync()
        // as part of the code

    

    // return type of transport.executeAsync() is
    // ListenableFuture<ResponseEntity<String>>
    private ListenableFuture<ResponseEntity<String>> doOutput()        
        return new SimpleAsyncTaskExecutor()
            .submitListenable(new Callable<ResponseEntity<String>>()  
            @Override
            public ResponseEntity<String> call() throws Exception 
                ....
                return responseEntity
            
        );
    

发生的情况是doOutput() 函数在auth.obtainAuth(); 之前被调用,当obtainAuth() 尝试调用doOutput() 时它返回null——很可能是因为doOutput之前已经在线执行了。我不确定如何在调用 executeAsync 时绑定/注入模拟类(传输)。

【问题讨论】:

一般来说,只要让 mock 对象立即返回一个值,如果需要的话,包装在 future 中。 @chrylis ya,这通常可以工作,但我们希望模拟对象 Auth 实际上不被使用(发出 http 请求)。超出测试范围。 这就是你使用模拟的原因;您实际上并没有输入发出请求的对象。听起来您可能并不完全清楚什么是模拟对象。 【参考方案1】:

我不确定我是否理解了这个问题,但正如chrylis 指出的那样,模拟对象会立即返回一个值。

单元测试应该有自己的上下文,并且不依赖于外部资源,因此测试异步调用本身没有意义。它应该返回不同的值,以便您能够测试使用它的类的行为。

要更好地理解模拟定义,请查看这篇文章:What is Mocking?

引用 Pro Spring MVC with Web Flow,应该进行单元测试

快速运行: 单元测试必须运行得非常快。如果需要等待 用于数据库 连接或外部服务器进程,或解析大文件,其 用处很快就会变得有限。测试应该提供一个 即时响应和即时满足。

零外部配置: 单元测试不得要求任何 外部配置文件,甚至不是简单的文本文件。测试的 配置必须由测试框架本身提供和设置 通过调用代码。目的是最大限度地减少 测试并消除外部依赖项(可以改变 时间,与测试不同步)。测试用例条件应该 在测试框架中表达,创建更具可读性的测试 条件。

独立于其他测试运行:单元测试必须能够在其中运行 完全隔离。换句话说,单元测试不能依赖于某些 在自身之前或之后运行的其他测试。每个测试都是独立的 单元。实际上,测试中的每个测试方法都应该是独立的 并且不依赖于另一种方法或正在运行的测试方法 一定的顺序。 • 依赖零外部资源:单元测试必须 不依赖于任何外部资源,例如数据库连接或 网页服务。这些资源不仅会减慢测试速度,而且 它们不在测试的控制范围内,因此不能保证 处于正确的测试状态。

保持外部状态不变:单元测试不能留下任何 证明它曾经运行过。单元测试被编写为可重复的,所以 他们必须自己清理。显然,这要容易得多 当测试不依赖外部资源(通常是 更难清理或恢复)。

尽可能测试最小的代码单元: 单元测试必须测试 最小的代码单元,以便在下面隔离代码 测试。在面向对象编程中,这个单元通常是一种 一个对象或类。编写单元测试以测试方法 独立于其他方法减少了代码行的数量 可能包含潜在的错误。

【讨论】:

以上是关于来自 void 类的模拟异步调用的主要内容,如果未能解决你的问题,请参考以下文章

对 Controller 函数进行异步调用 (void)。无法将控制权交还给 UI

使用 XCTest 进行异步方法测试

在 python 3.5 中模拟异步调用

React Jest:如何模拟返回数据的异步 API 调用?

异步任务尝试调用虚拟方法'void android.widget.TextView.setText(java.lang.CharSequence)'[重复]

如何等待来自 forEach 循环的多个异步调用?