为何被测的addSale()函数会修改测试文件中的测试数据对象?
为何被测的addSale()函数会修改测试文件中的测试数据对象?
这其实是JavaScript/TypeScript里对象引用传递的经典“坑”,我给你掰碎了说:
核心原因:对象是引用类型,不是值类型
你在测试文件里定义的standardSalesHistoryPintje是一个SalesHistory对象,属于引用类型。当你用Object.defineProperty把它赋值给salesHistoryService.salesHistories时,并不是把这个对象完整复制了一份过去,而是把它在内存中的“地址”传给了服务里的数组。换句话说:
- 测试文件里的
standardSalesHistoryPintje - 服务
salesHistories数组里的那个SalesHistory项
这两个变量其实指向的是内存中同一个对象,就像两个人拿着同一把钥匙开同一个箱子。
看addSale()里的操作是怎么修改原对象的
当你调用addSale()时,代码里会执行:
let salesHistory: SalesHistory = this.salesHistories.find(salesHistory => salesHistory.name === this.generalService.capitalizeFirstLetter(name)); // ... salesHistory.sales.push(sale);
这里的salesHistory就是从数组里找到的那个和standardSalesHistoryPintje同地址的对象。salesHistory.sales.push(sale)直接修改了这个对象的sales数组——既然是同一个对象,测试文件里的standardSalesHistoryPintje.sales自然也会跟着增加新的sale项,因为它们本来就是同一个东西。
为什么移到beforeEach就好了?
当你把standardSalesHistoryPintje的定义移到beforeEach里后,每次测试执行前都会重新创建一个全新的对象。也就是说,每个测试用的都是独立的“箱子”,它们的内存地址完全不同。哪怕某个测试修改了当前的对象,也不会影响其他测试的对象,自然就不会出现测试污染了。
再补个小总结
- 像数字、字符串这种值类型,变量存的是具体的值,赋值时会完整复制;
- 像对象、数组这种引用类型,变量存的是内存地址,赋值时传递的是地址,多个变量会指向同一个对象;
- 写测试时,共享的引用类型测试数据很容易导致交叉污染,最好每次测试都创建全新的实例。
内容来源于stack exchange
相关产品推荐
相关产品推荐

