Skip to main content

状态验证

什么是状态

状态指的就是,当前系统的属性或数据结构。即验证其是否有发生变化。

系统可以被理解成是一个状态机。

当我们和系统发生交互后,状态会改变。

黑盒验证

状态验证是一种黑盒验证。因为我们并不了解状态变化的实现细节,而是只验证最终的结果。

黑盒验证的好处是,我们可以和实现细节解耦,从而可以任意替换重构实现细节,只要结果能通过测试即可。

两种状态验证的场景

  1. 状态直接被存储在 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");
});