有啥方法可以根据参数修改 Jasmine 间谍?

Posted

技术标签:

【中文标题】有啥方法可以根据参数修改 Jasmine 间谍?【英文标题】:Any way to modify Jasmine spies based on arguments?有什么方法可以根据参数修改 Jasmine 间谍? 【发布时间】:2013-04-18 09:06:48 【问题描述】:

我想测试一个函数,它使用不同的参数两次调用外部 API 方法。我想用 Jasmine 间谍模拟这个外部 API,并根据参数返回不同的东西。茉莉花有没有办法做到这一点?我能想到的最好的方法是使用 andCallFake 进行破解:

var functionToTest = function() 
  var userName = externalApi.get('abc');
  var userId = externalApi.get('123');
;


describe('my fn', function() 
  it('gets user name and ID', function() 
    spyOn(externalApi, 'get').andCallFake(function(myParam) 
      if (myParam == 'abc') 
        return 'Jane';
       else if (myParam == '123') 
        return 98765;
      
    );
  );
);

【问题讨论】:

为什么你觉得and.callFake 是个黑客?对我来说似乎是一个很好/最好的答案。 【参考方案1】:

在 Jasmine 3.0 及以上版本中,您可以使用withArgs

describe('my fn', function() 
  it('gets user name and ID', function() 
    spyOn(externalApi, 'get')
      .withArgs('abc').and.returnValue('Jane')
      .withArgs('123').and.returnValue(98765);
  );
);

对于早于 3.0 的 Jasmine 版本,callFake 是正确的方法,但您可以使用对象来保存返回值来简化它

describe('my fn', function() 
  var params = 
    'abc': 'Jane', 
    '123': 98765
  

  it('gets user name and ID', function() 
    spyOn(externalApi, 'get').and.callFake(function(myParam) 
     return params[myParam]
    );
  );
);

根据 Jasmine 的版本,语法略有不同:

1.3.1:.andCallFake(fn) 2.0:.and.callFake(fn)

资源:

withArgs docs callFake docs andCallFake vs and.callFake

【讨论】:

现在是and.callFake - jasmine.github.io/2.2/…> 我必须返回不同的承诺,所以返回看起来略有不同:return q.when(params[myParam]);。否则,这是解决我的问题的一个点。我梦想的解决方案是更改“and.returnValue”调用。 感觉 jasmine 应该有更好的声明方式。喜欢spyOn(fake, 'method').withArgs('abc').and.returnValue('Jane')spyOn(fake, 'method').withArgs('123').and.returnValue(98765) @jrharshath .withArgs 在 jasmine 2.0 中不适合我 .withArgs 并不真正可用 - 我的意思是这样的方法在编写测试时会有意义。【参考方案2】:

您也可以使用$provide 创建间谍。并模拟使用and.returnValues 而不是and.returnValue 来传入参数化数据。

根据 Jasmine 文档: 通过将间谍与 and.returnValues 链接,对函数的所有调用将按顺序返回特定值,直到它到达返回值列表的末尾,此时它将为所有后续调用返回 undefined。

describe('my fn', () => 
    beforeEach(module($provide => 
        $provide.value('externalApi', jasmine.createSpyObj('externalApi', ['get']));
    ));

        it('get userName and Id', inject((externalApi) => 
            // Given
            externalApi.get.and.returnValues('abc','123');

            // When
            //insert your condition

            // Then
            // insert the expectation                
        ));
);

【讨论】:

这是正确的答案,因为测试应该始终准确地知道间谍将如何被调用,因此应该只使用returnValues 来支持多个调用 只是为了澄清 akhouri 的回答:此方法仅在 externalApi.get.and.returnValues('abc','123')it 函数中调用时有效。否则,如果您设置一个值列表,否则它永远不会起作用,因为运行测试的顺序是不可预测的。事实上,测试不应该依赖于它们的执行顺序。【参考方案3】:

在我的例子中,我有一个正在测试的组件,在它的构造函数中,有一个配置服务,其中有一个名为 getAppConfigValue 的方法,该方法被调用两次,每次使用不同的参数:

constructor(private configSvc: ConfigService) 
  this.configSvc.getAppConfigValue('a_string');
  this.configSvc.getAppConfigValue('another_string');

在我的规范中,我在 TestBed 中提供了 ConfigService,如下所示:


  provide: ConfigService,
  useValue: 
    getAppConfigValue: (key: any): any 
      if (key === 'a_string) 
        return 'a_value';
       else if (key === 'another_string') 
        return 'another_value';
      
    
   as ConfigService

所以,只要 getAppConfigValue 的签名与实际的 ConfigService 中指定的相同,函数内部的作用是可以修改的。

【讨论】:

以上是关于有啥方法可以根据参数修改 Jasmine 间谍?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Jasmine 间谍进行 Angular 2 组件测试“没有 Http 提供者!”错误

创建间谍时,Jasmine找不到功能

使用 Mockito 时,模拟和间谍有啥区别?

如何在茉莉花中重置间谍?

使用 Jasmine 在 AngularJS 中测试去抖函数从不调用该函数

茉莉花间谍对进口模块(打字稿)