如何模拟聚合物核心ajax,进行单元测试

时间:2014-07-02 12:47:01

标签: ajax unit-testing polymer

我正在为我的新聚合物项目建造脚手架,并正在考虑进行单元测试。我想我将使用业力/茉莉花组合。在http://japhr.blogspot.co.uk/2014/03/polymer-page-objects-and-jasmine-20.html有一篇有趣的帖子,我理解这个帖子足以让我开始,但我必须解决的关键问题是,我没有找到任何标准的方法来模拟ajax调用。< / p>

当我在JQuery Mobile项目中使用jasmine,standalone时,我能够直接使用Jasmine SpyOn来模拟JQuery.ajax调用。 Polymer有类似的东西吗?

我遇到了一个元素<polymer-mock-data>,但没有真正的文档,所以我无法弄清楚它们是否可以提供帮助

4 个答案:

答案 0 :(得分:3)

不要导入core-ajax/core-ajax.html,而是创建自己的core-ajax元素。

<polymer-element name="core-ajax" attributes="response">
<script>
  Polymer('core-ajax', {
    attached: function() {
      this.response = ['a', 'b', 'c'];
    }
  });
</script>
</polymer-element>

显然,这只是一个例子,实际的实现取决于所需的模拟行为。

这只是解决问题的一种方法,还有很多其他方法。我很有兴趣听到你在(方便)找到的东西。

答案 1 :(得分:1)

事实证明,Jasmine2.0有一个Jasmine-ajax插件,可以模拟全局XMLHttpRequest。 core-ajax在引擎盖下使用它,所以我可以直接接听电话。

效果很好,在您调用beforeEach套件顶部的jasmine.Ajax.install函数和afterEach函数中调用jasmine.Ajax.uninstall,它会自动替换XMLHttpRequest

时序也很重要,因为你需要确保在被测元素使用它之前模拟了Ajax调用。我使用一个单独的函数来实现它,以专门加载包含被测元素的fixture,该元素在调用jasmine.Ajax.install后调用。我使用特殊的安装脚本

(function(){
  var PolymerTests = {};
  //I am not sure if we can just do this once, or for every test.  I am hoping just once
  var script = document.createElement("script");
  script.src = "/base/components/platform/platform.js";
  document.getElementsByTagName("head")[0].appendChild(script);

  var POLYMER_READY = false;
  var container;  //Used to hold fixture
  PolymerTests.loadFixture = function(fixture,done) {
    window.addEventListener('polymer-ready', function(){
      POLYMER_READY = true;
     done();
    });
    container = document.createElement("div");
    container.innerHTML = window.__html__[fixture];
    document.body.appendChild(container);
    if (POLYMER_READY) done();
  };
  //After every test, we remove the fixture
  afterEach(function(){
    document.body.removeChild(container);
  });

  window.PolymerTests = PolymerTests;

})();

这里唯一需要注意的是,夹具文件已由karma html2js预处理器加载,后者将它们加载到window.__html__数组中,我们使用该代码将其添加到测试上下文< / p>

我的测试套件就是这样

describe('<smf-auth>',function(){
  beforeEach(function(done){
    jasmine.Ajax.install();
    PolymerTests.loadFixture('client/smf-auth/smf-auth-fixture.html',done);
  });
  afterEach(function(){
    jasmine.Ajax.uninstall();
  });
  describe("The element authenticates",function(){
    it("Should Make an Ajax Request to the url given in the login Attribute",function(){
      var req = jasmine.Ajax.requests;
      expect(req.mostRecent().url).toBe('/football/auth_json.php'); //Url declared in our fixture
    });

  })
});

答案 2 :(得分:0)

对于这个答案,我采取了完全不同的方法。灵感来自Web Component Tester,其中包括sinon的功能。 sinon包括调用sinon.useFakeXMLHttpRequest来替换core-ajax使用的标准xhr对象并返回其上的响应的能力。

据我所知,还没有完全运行使用它的模块测试,Web Component Tester在node.js上下文中运行sinon所以随它提供的sinon的构建可以“需要”各种sinon组件。在普通的浏览器环境中,这不起作用,我正在寻找一种方法,允许我手动运行我正在开发的应用程序,而没有运行php的服务器..

但是,从Bower下载并安装来自sinonjs.org网站的实际版本,确实提供了一个完全构建的sinon,它将在Web服务器的上下文中运行。

所以我可以在主index.html文件中包含以下脚本

  <!--build:remove -->
  <script type="text/javascript" src="/bower_components/sinon-1.14.1/index.js"></script>
  <script type="text/javascript" src="/fake/fake.js"></script>
  <!--endbuild-->

这是由gulp构建scrips自动删除,然后假JS有以下内容

var PAS = (function (my) {
  'use strict';
  my.Faker = my.Faker || {};
  var getLocation = function(href) {
    var a = document.createElement('a');
    a.href = href;
    return a;
  };
  sinon.FakeXMLHttpRequest.useFilters = true;
  sinon.FakeXMLHttpRequest.addFilter(function(method,url){
      if(method === 'POST' && getLocation(url).pathname.substring(0,7) === '/serve/') {
        return false;
      }
      return true;
  });
  var server = sinon.fakeServer.create();
  server.autoRespond = true;


  my.Faker.addRoute = function(route,params,notfound){
    server.respondWith('POST','/serve/' + route + '.php',function(request){
      var postParams = JSON.parse(request.requestBody);
      var foundMatch = false;
      var allMatch;
      /*
       * First off, we will work our way through the parameter list seeing if we got a parameter
       * which matches the parameters received from our post.  If all components of a parameter match,
       * then we found one
       */

      for(var i=0; i <params.length; i++) {
        //check to see parameter is in request
        var p = params[i][0];
        allMatch = true;  //start of optimisic
        for(var cp in p ) {
          //see if this parameter was in the request body
          if(typeof postParams[cp] === 'undefined') {
            allMatch = false;
            break;
          }


          if(p[cp] !== postParams[cp]) {
            allMatch = false;
            break;
          }
        }
        if (allMatch) {
          request.respond(200,{'Content-Type':'application/json'},JSON.stringify(params[i][1]));
          foundMatch = true;
          break;
        }

      }
      //see if we found a match.  If not, then we will have to respond with the not found option
      if (!foundMatch) {
        request.respond(200,{'Content-Type':'application/json'},JSON.stringify(notfound));
      }
    });

  };
  return my;
})(PAS||{});
/**********************************************************************
  Thses are all the routinee we have and their responses.
 **********************************************************************/
PAS.Faker.addRoute('logon',[
    [{password:'password1',username:'alan'},{isLoggedOn:true,userID:1,name:'Alan',token:'',keys:['A','M']}],
    [{username:'alan'},{isLoggedIn:false,userID:1,name:'Alan'}],
    [{password:'password2',username:'babs'},{isLoggedOn:true,userID:2,name:'Barbara',token:'',keys:['M']}],
    [{username:'babs'},{isLoggedIn:false,userID:2,name:'Barbara'}]
    ],{isLoggedOn:false,userID:0,name:''});

PAS函数初始化一个sinon假服务器,并提供一种使用addRoute函数提供测试用例的方法。对于给定的路由,它会检查可能的POST参数组合列表,一旦找到它,就会发出响应。

在这种情况下,测试/serve/logon.php以获取用户名和密码的各种组合。它只检查特定条目中的实际参数。

因此,如果username =“alan”和password =“password1”,则会发出第一个响应,但如果用户名是“alan”并且提供了任何其他密码 - 因为未选中,则第二个模式匹配并且响应制定了这种模式。

如果非模式匹配,则最后一个“notfound”参数是所做的响应模式。

我相信如果我愿意的话,我可以在我的模块测试装置中使用相同的技术,但我更有可能做更具体的sinon间谍并检查该模式下的实际参数

答案 3 :(得分:0)

对于0.8,link显示如何使用sinon。

由于SO不喜欢仅限链接的答案,因此我在下面复制了他们的代码。但是我强烈建议你去上面链接的源码,因为0.8组件目前处于高通量状态。

      var jsonResponseHeaders = {
        'Content-Type': 'application/json'
      };
      var ajax;
      var request;
      var server;

      setup(function () {
        server = sinon.fakeServer.create();
        server.respondWith(
          'GET',
          '/responds_to_get_with_json',
          [
            200,
            jsonResponseHeaders,
            '{"success":true}'
          ]
        );

        server.respondWith(
          'POST',
          '/responds_to_post_with_json',
          [
            200,
            jsonResponseHeaders,
            '{"post_success":true}'
          ]
        );

        ajax = fixture('TrivialGet');
      });

      teardown(function () {
        server.restore();
      });

      suite('when making simple GET requests for JSON', function () {
        test('has sane defaults that love you', function () {
          request = ajax.generateRequest();

          server.respond();

          expect(request.response).to.be.ok;
          expect(request.response).to.be.an('object');
          expect(request.response.success).to.be.equal(true);
        });

        test('will be asynchronous by default', function () {
          expect(ajax.toRequestOptions().async).to.be.eql(true);
        });
      });