在Angularjs中,你如何改变每次测试的模拟服务?

时间:2017-10-26 23:20:38

标签: javascript angularjs unit-testing angular-services

代码示例

这可能在代码中有更好的解释,所以我在下面列出了一个详细的抽象示例 - 我的问题在评论中重复了。

示例摘要

例如,您模拟了一个相当复杂的模拟服务,并且在第一个测试中,您希望模拟服务为一个函数提供正结果(通过下面示例中的返回代码200)。在第二个测试中,您希望相同的函数返回负结果,例如500.

我发现我可以简单地注入提供程序并覆盖方法,但这是正确的方法吗?见"测试2"下面。

describe('CommentArea', function() {

  var controller
  beforeEach(function() {
    module('app', function($provide) {
      // Base mock definition
      $provide.provider('comments', function() {
        this.$get = function() {
          return {
            create: function() {
              return new Promise(function(resolve) {
                resolve({ code: 200 })
              })
            },
            delete: function() {
              return new Promise(function(resolve) {
                resolve({ code: 200 })
              })
            }
          }
        }
      })
    })

    inject(function($componentController) {
      controller = $componentController('CommentArea')
    })
  })

  // Start tests
  //
  // Test 1 - Use the above mocked service "as is" - happy path scenario
  //
  it('appends comment when successful', function() {
    expect(controller.commentCount).toEqual(0)
    controller.create() // uses the comments service create method
    expect(controller.commentCount).toEqual(1)    
  })

  // Test 2 - Use the above mocked service with a slight modification
  // This time the create function will fail
  //
  it('does not append comment when unsuccessful', inject(function(comments) {
    // overwrite for failure condition here
    // QUESTION - is this acceptable? It seems odd just overwriting it
    // so directly
    comments.create = function () {
      return new Promise(function(resolve) {
        resolve({ code: 500 })
      })
    }

    expect(controller.commentCount).toEqual(0)
    controller.create() // uses the comments service create method
    expect(controller.commentCount).toEqual(0)    
  }))
})

1 个答案:

答案 0 :(得分:1)

通常这意味着不应在beforeEach中定义模拟的返回值。

其中一种方法是使函数返回在公共函数范围(describe块)中定义的局部变量:

var createValue;
...
beforeEach(module('app', { comments: {
  create: function () { return createValue }, ...
}))
...
createValue = Promise.resolve(200);
comments.create();

局部变量有缺点。如果在下次测试中错误地重新定义createValue,则测试可能会被交叉污染。

而且,这种模拟并不能解决一项重要任务;嘲笑的功能没有被发现。

这正是茉莉花间谍应该解决的任务:

beforeEach(function () {
  module('app', { comments: jasmine.createSpyObj('comments', ['create', 'delete']) });
});
在这种情况下,

module应该用函数包装,因为应该在每个beforeEach调用上创建一个新的间谍对象。

然后返回值就地定义:

comment.create.and.returnValue(Promise.resolve(200))
comments.create();