mock 框架入门
使用 mock 框架
mock 框架本身是仓颉标准库中单元测试的一部分。使用 mock 框架前,需将 unittest.mock.*
和 unittest.mock.mockmacro.*
导入到测试文件中。
如果使用 cjpm 工具,仅需运行 cjpm test
命令即可自动启用 mock 框架。
如果直接使用 cjc ,参见使用 cjc。
示例
常见 mock 测试用例:
- 调用mock 构造函数创建 mock/spy 对象。
- 调用配置 API设置 mock 行为。
- 使用 mock 对象替代测试代码依赖。
- (可选)调用验证 API来验证测试代码与 mock/spy 对象之间的交互。
以如下简单API为例:
public interface Repository {
func requestData(id: UInt64, timeoutMs: Int): String
}
public class Controller {
public Controller(
private let repo: Repository
) {}
public func findData(id: UInt64): ?String {
try {
return repo.requestData(id, 100)
}
catch (e: TimeoutException) {
return None
}
}
}
public class TimeoutException <: Exception {}
如果 Repository
实现不理想,比如可能包含复杂的依赖关系,实现在其他包中,或者测试太慢,mock 框架可以在不创建依赖的情况下测试 Controller
。
测试 findData
方法:
//导入mock框架包
import std.unittest.mock.*
import std.unittest.mock.mockmacro.*
@Test
class ControllerTest {
let testId: UInt64 = 100
let testResponse = "foo"
@TestCase
func testFindSuccessfully() {
//只需要创建mock,不用创建真正的Repository
let repository = mock<Repository>()
//使用@On宏配置testData行为
@On(repository.requestData(testId, _)).returns(testResponse)
//创建真正的Controller测试以便测试实际的实现
let controller = Controller(repository)
//运行测试代码
let result = controller.findData(testId)
//对结果运行断言
@Assert(result == Some(testResponse))
}
@TestCase
func testTimeout() {
let repository = mock<Repository>()
//设置getData抛出异常
@On(repository.requestData(testId, _)).throws(TimeoutException())
let controller = Controller(repository)
//底层实现抛出异常时,测试行为
let result = controller.findData(testId)
//对结果运行断言
@Assert(result == None)
}
}