如何模拟polymer core ajax进行单元测试

如何模拟polymer core ajax进行单元测试,ajax,unit-testing,polymer,Ajax,Unit Testing,Polymer,我正在为我的新聚合物项目搭建脚手架,并且正在考虑单元测试。我想我会使用因果报应和茉莉花的组合。有一篇有趣的帖子,我对此有足够的了解,可以让我开始学习,但我必须解决的关键问题是如何模拟ajax调用,目前还没有找到任何标准的方法 当我在JQuery移动项目上使用jasmine,standalone时,我能够直接使用jasmine SpyOn功能模拟JQuery.ajax调用。聚合物也有类似的情况吗 我遇到了一个元素,但是没有关于它的真正文档,因此我无法确定它们是否有助于而不是导入核心ajax/cor

我正在为我的新聚合物项目搭建脚手架,并且正在考虑单元测试。我想我会使用因果报应和茉莉花的组合。有一篇有趣的帖子,我对此有足够的了解,可以让我开始学习,但我必须解决的关键问题是如何模拟ajax调用,目前还没有找到任何标准的方法

当我在JQuery移动项目上使用jasmine,standalone时,我能够直接使用jasmine SpyOn功能模拟JQuery.ajax调用。聚合物也有类似的情况吗


我遇到了一个元素
,但是没有关于它的真正文档,因此我无法确定它们是否有助于而不是导入
核心ajax/core ajax.html
,创建您自己的核心ajax元素

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

聚合物(“核心-ajax”{
附:函数(){
this.response=['a','b','c'];
}
});
显然,这只是一个示例,实际实现取决于所需的模拟行为


这只是解决问题的一种方法,还有很多其他方法。我很想听听你觉得方便些什么。

事实证明,Jasmine2.0有一个Jasmine ajax插件,可以模拟全局XMLHttpRequest。CoreAJAX在幕后使用它,所以我可以直接接到电话

它工作得很好,在调用jasmine.Ajax.install的套件顶部的
beforeach
函数中,以及在调用
jasmine.Ajax.uninstall
函数之后的
函数中,它会自动替换XMLHttpRequest

计时也很重要,因为您需要确保在被测元素使用Ajax调用之前已经模拟了它。我使用一个单独的函数专门加载包含被测元素的fixture,该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预处理器加载,该预处理器将它们加载到
窗口中

我的测试套件就是这样

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
    });

  })
});
描述(“”,函数(){
每次之前(功能完成){
jasmine.Ajax.install();
loadFixture('client/smf auth/smf auth fixture.html',完成);
});
之后(函数(){
jasmine.Ajax.uninstall();
});
描述(“元素身份验证”,函数(){
它(“应该对登录属性中给定的url发出Ajax请求”,function(){
var req=jasmine.Ajax.requests;
expect(req.mostRecent().url).toBe('/football/auth_json.php');//在我们的fixture中声明的url
});
})
});

对于这个答案,我采取了完全不同的方法。灵感来自Web组件测试仪,它将sinon包括在其能力范围内。sinon包括调用sinon.usefakeMlHttpRequest以替换core ajax使用的标准xhr对象并返回相应响应的功能

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

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

因此,我可以在我的主index.html文件中包含以下脚本


它会被gulp build scrips自动删除,然后fake JS包含以下内容

var PAS=(函数(my){
"严格使用",;
my.Faker=my.Faker | |{};
var getLocation=函数(href){
var a=document.createElement('a');
a、 href=href;
返回a;
};
sinon.FakeXMLHttpRequest.useFilters=true;
sinon.FakeXMLHttpRequest.addFilter(函数(方法,url){
if(方法=='POST'&&getLocation(url).pathname.substring(0,7)=='/service/')){
返回false;
}
返回true;
});
var server=sinon.fakeServer.create();
server.autoRespond=true;
my.Faker.addRoute=函数(路由、参数、未找到){
server.respondWith('POST','/service/'+route+'.php',函数(请求){
var postParams=JSON.parse(request.requestBody);
var foundMatch=false;
var-allMatch;
/*
*首先,我们将通过参数列表查看是否有参数
*它与从我们的帖子中收到的参数匹配。如果参数的所有组件都匹配,
*然后我们找到了一个
*/
对于(var i=0;i对于0.8,演示如何使用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);
        });
      });

谢谢-当你知道答案的时候,这是很明显的。真正能够测试第一个元素的过程有点慢,因为我正在一次学习咕噜声、因果报应和聚合物,并且只有空闲时间去做。但这对我来说是一个足够的指针,我发现这种方法在实践中相当困难-因为通常的方法是在包含元素定义的html文件中导入核心ajax,我们不想仅仅为了运行测试而改变它。我想我可能想在核心ajax原型上更改go方法,但在我的元素在ready回调中调用它之前,还不知道如何实现它。