How to test json inside function using jasmine?

↘锁芯ラ 提交于 2019-12-25 10:26:09

问题


This is the code that I want to test:

function loadNotification(searchOption, searchKey) {
   var url = '@URLs.API.Notifications.Past' + '?searchOption=' + searchOption + '&searchValue=' + searchKey;
   $.getJSON(url)
      .done(function (nData) {
        //some code here
      })
      .fail(function (jqXHR, status, error) {
        showError('There was an error while fetching the records. Please try after some time. (' + jqXHR.status + ':' + jqXHR.statusText + ')');
      });
}

Using jasmine, how do I test if the json file fails or not? I was thinking of using .done and .fail but I'm not sure if it's possible. I don't know much about json. Can anyone help me out?


回答1:


when testing AJAX requests (and similar, fetching json file etc.), it's always a good idea to check that your code can handle both done and fail. You should also mock the data that you test, don't rely much on actual endpoints in your application or files that it tries to download. You want the test to run as fast as possible.

Using Jasmine you can do a few things:

using a spy:

spyOn is a function that can stub a given function and track what kind of arguments were passed to it, can see what other function called it and even return a specific value when the code that it's spied on executes.

You could use a spy to see that the $.get request will happen, and then you can say return a specific value, and continue testing the program.

using Jasmine Ajax plugin

This is what I like to use in my tests. Jasmine has a very nice plugin ajax.js. It simplifies testing any ajax functionality. What I like to do is to mock the actual request, so when your code would tries to get a file/response, the code will ignore the actual call and mock it, returning fake data that you can specify.

Before I start, I also like to have my ajax method in a separate function, it will just return a promise. It's much easier to read/test/maintain, so for example you could rewrite it like:

this.loadNotificationCall = function(searchOption, searchKey) {
    var url = '@URLs.API.Notifications.Past' + '?searchOption=' + searchOption + '&searchValue=' + searchKey;
    return $.getJSON(url)
} 

this.loadNotification() {
    return this.loadNotificationCall()
        .done(function (nData) {
            //some code here
        })
        .fail(function (jqXHR, status, error) {
            showError('There was an error while fetching the records. Please try after some time. (' + jqXHR.status + ':' + jqXHR.statusText + ')');
        });
}

If you load your test app with dummy data, I guess you expect the ajax request file to have a specific path.

You're looking at most basic, default version of what you can output from

'@URLs.API.Notifications.Past' + '?searchOption=' + searchOption + '&searchValue=' + searchKey;

Let's say it's something like

//'someapi?searchOption=1&searchValue=abc'

That url needs to exactly match to what will your application would attempt to contact. Check your debug/fiddler and see what is that just in case. If it's not matched (including the data it's trying to send) the mock will fail, and test will timeout. The error usually looks like Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

Once you get that right, you can mock that url in the following example:

describe('when user gets the data', function() {

var sut = null;
var testCall = null;
var dummyData = {
    name: 'Jon Snow'
};
beforeEach(function() {
    jasmine.Ajax.install();
    jasmine.Ajax.stubRequest("someapi?searchOption=1&searchValue=abc").andReturn({
            responseText: JSON.stringify(dummyData)
    });

    sut = new yourApplication();
    testCall = sut.loadNotification();
});

afterEach(function() {
    jasmine.Ajax.uninstall();
});

// actual tests here

});

I'm also pretty sure that you can use wildcards in those mock urls, so this should also be valid: jasmine.Ajax.stubRequest("someapi?(.*)").andReturn(//

So what happens now is, if you test something that will call your method with $.get, the request won't happen to your server, but instead it will be mocked and our dummy data will be returned. In this example it's a simple object with name: 'Jon Snow'

Now, you want to have a test that looks something like this:

it('should populate name', function(done) {
    testCall
        .done(function() {
            expect(sut.name).toEqual('Jon Snow');
            done();
        });
});

You pass done argument to the test, so that it won't finish until the call is finished. If you debug it in your browser, you will see that code in your file will go inside done method and continue working as it was a real request. The data in done(nData) will become our dummy object with name: Jon Snow.

If you wanted to test a failing code, you can add some additional settings to ajax plugin:

jasmine.Ajax.stubRequest("someapi?searchOption=1&searchValue=abc").andReturn({
    status: 500,
    responseText: "{}"
});

I hope I didn't bore you with this much, I know that there are simplier methods (such as just doing $.spy on 'ajax' and seeing the most recent call etc. but I like my method, has worked very well and I can test multiple calls, chained calls, and many more cool scenarios.



来源:https://stackoverflow.com/questions/36943055/how-to-test-json-inside-function-using-jasmine

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!