状态验证
什么是状态
状态指的就是,当前系统的属性或数据结构。即验证其是否有发生变化。
系统可以被理解成是一个状态机。
当我们和系统发生交互后,状态会改变。
黑盒验证
状态验证是一种黑盒验证。因为我们并不了解状态变化的实现细节,而是只验证最终的结果。
黑盒验证的好处是,我们可以和实现细节解耦,从而可以任意替换重构实现细节,只要结果能通过测试即可。
两种状态验证的场景
- 状态直接被存储在 SUT 里面。
SUT: System Under Test.
这个术语用于指代正在被测试的系统、模块、类或方法。 简而言之,SUT 是您的测试目标。
+--------------------------+
| SUT |
| |
| old_state ===> new_state |
| |
| |
+--------------------------+
2.状态没被存储在 SUT 里,而是在 DOC 里面。
DOC: Depended-on Component(依赖组件)
DOC 是 SUT 所依赖的任何外部组件或系统。 比如,数据库,文件系统,网络调用或者其他外部服务和模块等任何外部资源。
通常会使用 Mock 或者 Stub 来替换掉真实的 DOC 逻辑。
+---------+ +---------+
| SUT | | DOC |
| | ===> | State |
| | | |
+---------+ +---------+
下面用代码来理解这两种场景。
第一种场景
count
状态是私有的,那要如何测试呢?
我们可以添加一个 API 将 count
状态暴露出去。
// counter.ts
export class Counter {
private count: number;
constructor() {
this.count = 0;
}
increment(): void {
this.count++;
}
getCount() {
return this.count;
}
}
// counter.spec.ts
import Counter from "../counter.ts";
it("increment", () => {
const counter = new Counter();
counter.increment();
expect(counter.getCount()).toBe(1);
});
第二种场景
database.ts
是 SUT,其中 dataStore
就是需要验证的状态。
UserService.ts
就是一个 DOC。
// database.ts
export interface User {
id: number;
name: string;
}
export class Database {
private dataStore: User[] = [];
addUser(user: User): void {
this.dataStore.push(user);
}
getUser(id: number): User | undefined {
return this.dataStore.find((user) => user.id === id);
}
}
// UserService.ts
import { Database, User } from "./database";
export class UserService {
constructor(private database: Database) {}
createUser(name: string): User {
const id = Math.floor(Math.random() * 1000);
const newUser: User = { id, name };
this.database.addUser(newUser);
return newUser;
}
}
那在单元测试里,就需要这样去找状态:
// UserService.spec.ts
it("should create a new user", () => {
const database = new Database();
const userService = new UserService(database);
const user = userService.createUser("nansen");
const userName = database.getUser(user.id)?.name;
expect(userName).toBe("nansen");
});