如何使用Jasmine对Knockout.js订阅函数进行单元测试?

时间:2016-10-17 13:02:29

标签: javascript c# unit-testing knockout.js jasmine

我有一个淘汰视图模型,它有一些订阅函数,可以在获取父选择的更改后更新一些默认选择。

但我不确定如何调用该函数并伪造依赖关系以进行测试。

此代码snippit类似于函数,但不是确切的函数。它订阅了SelectedParentOption observable,当它更改为检查可用内容并选择一个新值时。

        //When selection changes select default for remaining selection
        self.ServerModel.ProductModel.SelectedParentOption.subscribe(function () {
            // Loop through options returned by function checking for correct key
            self.availableOptions().forEach(function (option) {
                if (option.Key == 1)
                    // Assign default selection
                    self.ServerModel.ProductModel.SelectedChildOption(option);
            }
        });

这是Jasmine单元测试

        it("Selection set to default after change", function () {
        // Spy on available options to dictate what's available
        spyOn(testModel, 'availableOptions').and.returnValue(TestOptions);
        // Change selection
        ServerModel.ProductModel.SelectedParentOption(Option1);
        // Call function
        ServerModel.ProductModel.SelectedParentOption.subscribe();
        // Verify default was selected
        expect(ServerModel.ProductModel.SelectedChildOption()).toBe(ExpectedOption);
    });

目前,这会更改选项,但订阅代码似乎根本没有受到影响。

2 个答案:

答案 0 :(得分:1)

我确实没有发现您的代码有任何问题,另外您在设置可观察的值后不需要致电subscribe();淘汰赛为你做到了。 subscribe方法用于注册处理新值的函数。

重要的是要记住,如果将observable设置为与它已经存在的值相同,订阅将不会被触发。

因此,在您的情况下:如果在SelectedParentOption() === Option1评论之前Change selection,则不会重置。如果您想手动触发它,请使用valueHasMutated()(而不是使用subscribe()的地方)

查看这些(快速和肮脏)测试。

测试2和3相互矛盾;其中只有一个会通过。他们描述了不同的行为:

  • 2:仅在父选择实际更改
  • 时才重置
  • 3:当有人设置父选择时总是重置,即使它与之前的值相同

我可以想象测试2更好地描述了您正在寻找的内容,但如果您希望测试3通过,您可以将您的observable扩展为始终通知其订阅者。取消注释ViewModel中的注释以查看差异。



function ViewModel() {
  this.selectedParent = ko.observable(0)/*.extend({notify: 'always'})*/;

  this.children = [{ key: 0 }, { key: 1}, { key: 2 }];

  this.selectedChild = ko.observable(null);

  this.selectedParent.subscribe(function() {
    this.selectedChild(this.children.find(function(child) {
      return child.key === 1;
    }));
  }, this)
}

describe('Subscription test', function() {
  var vm;

  beforeEach(function() {
    vm = new ViewModel();
  });

  it("should reset child selection to child 1 when parent changes", function() {
    expect(vm.selectedChild()).toBe(null);
    vm.selectedParent(1);
    expect(vm.selectedChild().key).toBe(1);

  });

  it("should not reset child when re-setting the same parent selection", function() {
    vm.selectedParent(1);
    vm.selectedChild(vm.children[2]);

    expect(vm.selectedChild().key).toBe(2);

    // Same primitive, won't trigger the subscription
    vm.selectedParent(1);
    expect(vm.selectedChild().key).toBe(2);

  });

  // To fix this test, uncomment .extend in selectedParent
  it("should always reset child when re-setting the same parent selection", function() {
    vm.selectedParent(1);
    vm.selectedChild(vm.children[2]);

    expect(vm.selectedChild().key).toBe(2);

    vm.selectedParent(1);
    expect(vm.selectedChild().key).toBe(1);
  });

  it("should initialize without a selection", function() {
    expect(vm.selectedChild()).toBe(null);
  });

  it("should set selections", function() {
    vm.selectedChild(vm.children[2]);
    expect(vm.selectedChild().key).toBe(2);
  });

});

<script src="http://searls.github.io/jasmine-all/jasmine-all-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

在更改观察值之前,您应该致电.subscribe()。它仅在订阅设置后检测更改。试试这个:

// enable subscription ServerModel.ProductModel.SelectedParentOption.subscribe(); // Change selection ServerModel.ProductModel.SelectedParentOption(Option1); // Verify default was selected expect(ServerModel.ProductModel.SelectedChildOption()).toBe(ExpectedOption);