6

我有以下角度服务及其茉莉花测试。测试调用 f1() 并监视 f2()。函数 f2 接受变量 v2 并对其进行修改(将字段 a 设置为 3)。函数 f2 应该用 v2 调用(如 f1 中声明的那样),但我的测试在toHaveBeenCalledWith上失败,并说实际调用是在 f2 函数调用之后使用对象。茉莉花在函数调用后是否匹配 .toHaveBeenCalledWith 的参数,这不应该是推荐的方式,或者我在这里犯了一些错误。

服务:

export class JasmineTestClass{
    constructor(){
    }
    f2(v2){
        v2.a = 3
    };
    f1(v1){
        let v2 = {
            a:30
        };
        this.f2(v2);
    }
}

测试:

describe('Test', () => {
    let service: JasmineTestClass;
    beforeEach(() => {
        service = new JasmineTestClass();
        spyOn(service, 'f2').and.callThrough();
    });
    let v1 = {
        a:2, b:3
    };
    let v2 = {
        a:30
    };
    it('should succeed', () => {
        service.f1(v1);
        expect(service.f2).toHaveBeenCalledWith(v2);    //this is failing
    });
})

日志:

Test should succeed FAILED

Expected spy f2 to have been called with [Object ({a:30})] but actual calls were [Object ({a:3})]

请注意,我在测试时在 Chrome 中进行了调试,并且使用 v2 = {a:30} 调用了函数 f2()。

4

1 回答 1

6

toHaveBeenCalledWith断言时匹配调用参数。

Jasmine 间谍只是在内部保存参数引用。调用参数可以通过记录service.f2.calls.all()对象进行跟踪。

这里的问题是f2修改了通过引用传递给它的对象。调用后的任何地方都不存在原始v2的。v2.a === 30f2

这种情况的正确策略是创建细粒度的测试,每个单元(方法)一个测试。使用的事实callThrough表明单元不是相互隔离的spyOn(service, 'f2'),默认情况下只使用存根是个好主意:

it('should succeed', () => {
  service.f1(v1);
  expect(service.f2).toHaveBeenCalledWith({ a:30 });
});

it('should succeed', () => {
  const obj = { a:30 };
  service.f2(obj);
  expect(obj).toEqual({ a:3 });
});

现在我们正在测试这两种方法到底发生了什么。

于 2018-02-04T12:11:15.920 回答