Mic*_*arf 6 unit-testing typescript mobx
注意:这不是真正的应用程序,而是问题的简化版本。
我有一个简单的伪造的Todo应用程序,用于@computed获取的价值TodoItemComputed.isSelected:
import { computed, observable, action } from 'mobx';
export class TodoItemComputed {
readonly id: string;
readonly list: TodoListComputed;
constructor(id: string, list: TodoListComputed) {
this.id = id;
this.list = list;
}
// ** This is the attribute we are interested in and we want to test!
@computed
get isSelected() {
return this.id === this.list.selectedId;
}
}
export class TodoListComputed {
@observable.shallow
private serverData: string[] = [];
@observable
selectedId = '';
@action
setServerData(data: string[]) {
this.serverData = data;
}
@action
setSelected(id: string) {
this.selectedId = id;
}
@computed
get todoItems() {
return this.serverData.map(d => new TodoItemComputed(d, this));
}
}
Run Code Online (Sandbox Code Playgroud)
测试TodoItemComputed.isSelected我可以做这样的事情:
import { TodoListComputed } from '../TodoExample';
// Using jesthere, but the test framework should not matter...
describe('isSelected', function() {
it('should have no Item selected initially', function() {
const todoList = new TodoListComputed();
todoList.setServerData(['foo', 'bar']);
expect(todoList.todoItems[0].isSelected).toBe(false);
expect(todoList.todoItems[1].isSelected).toBe(false);
});
it('should select the correct item', function() {
const todoList = new TodoListComputed();
todoList.setServerData(['foo', 'bar']);
todoList.setSelected('bar');
expect(todoList.todoItems[0].isSelected).toBe(false);
expect(todoList.todoItems[1].isSelected).toBe(true);
});
});
Run Code Online (Sandbox Code Playgroud)
由于某些原因,我必须重构我的应用程序,并且我使用反应而不是计算(例如,因为我必须显示10,000个项目,并且选择迅速改变,并且调用TodoListComputed.setSelected导致所有项目上的所有计算都重新运行)。
因此,我将其更改为使用reaction(似乎在使用时autorun可以使用与computed版本相同的测试):
import { autorun, computed, observable, action } from 'mobx';
export class TodoItemReaction {
readonly id: string;
@observable
isSelected = false;
constructor(id: string) {
this.id = id;
}
@action
setSelected(isSelected: boolean) {
this.isSelected = isSelected;
}
}
export class TodoListReaction {
@observable.shallow
private serverData: string[] = [];
@observable
selectedId = '';
constructor() {
reaction(
() => [this.setSelected, this.todoItems],
() => {
this.todoItems.forEach(t => {
t.setSelected(t.id === this.selectedId);
});
}
);
}
@action
setServerData(data: string[]) {
this.serverData = data;
}
@action
setSelected(id: string) {
this.selectedId = id;
}
@computed
get todoItems() {
return this.serverData.map(d => new TodoItemReaction(d));
}
}
Run Code Online (Sandbox Code Playgroud)
问题:如何测试autorun版本?
奖励问题:如何测试无论我使用autorun还是没关系的代码computed?
无论您如何实现,您都应该能够测试这两种实现。顺便说一句,我认为这对于任何测试都应该是正确的,避免“了解”实现,测试需求。
当您使用. 在反应上设置项目的 . 时,您的实现的问题是@computed在列表上的使用。这将导致重新计算。这是因为您在初始化类时设置了。todoItemsisSelectedsetSelected@computed todoItemsisSelectedfalse
换句话说,@computed todoItems正在“监听”每个项目的变化@observable isSelected。
这是一个非常简单快速的实现(没有reaction):
export class TodoItem {
readonly id: string;
@observable isSelected = false;
constructor(id: string) {
this.id = id;
}
@action
setSelected(isSelected: boolean) {
this.isSelected = isSelected;
}
}
export class TodoList {
@observable.shallow
todoItems: TodoItem[] = [];
@action
setServerData(data: string[]) {
this.todoItems = data.map((d) => new TodoItem(d));
}
@action
setSelected(id: string) {
this.todoItems.forEach((t) => t.setSelected(t.id === id));
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
378 次 |
| 最近记录: |