4

jasmine を使用して単体テストを行い、sinon を使用して ajax 呼び出しをモックしています。ただし、これにより、テスト ケースが繰り返し呼び出される無限ループが発生します。ajax 呼び出しは同期的に行われます。ajax 呼び出しを非同期に変更すると、無限ループは発生しません。どんな助けや指針も大歓迎です!

ajax 呼び出しを使用した関数は次のとおりです。

define([
    // Utils
    'util/logging',
    // Project Dependencies
    'views/core/baseView',
    'i18n!i18n_DNA/nls/basePage',
    'i18n!i18n_DNA/nls/consentSettingsView',
    'duster!templates/widgets/testSettings/consentSettings.dust.html'
], function (Log, BaseView, i18n_basePage, i18n_consentSettingsView, template) {
    'use strict';

    // ConsentSettingsView
    // -----------------------------------------------------------------------------------------
    return BaseView.extend({

        events: {
            'click #deleteTestButton': 'deleteTestModal'
        },

        className: 'connectDelete',

        // initialize()
        // ---------------------------------------------------------------------------------------
        initialize: function () {

            this.hasConsented = this.options.hasConsented;
            this.testId = this.options.testId;
            this.appRouter = this.options.appRouter;

            // Call `super()`.
            BaseView.prototype.initialize.call(this);
        },

        // render()
        // ---------------------------------------------------------------------------------------
        render: function () {

            var self = this;

            var context = {
                i18n_basePage: i18n_basePage,
                i18n_consentSettingsView: i18n_consentSettingsView,
                hasConsented: this.hasConsented,
                testId: this.testId
            };

            dust.render('templates/widgets/testSettings/consentSettings.dust.html', context, function (err, out) {
                if (err) {
                    console.error(err);
                } else {
                    self.$el.html(out);
                }
            });

            return self;
        },

        // deleteTestModal()
        // ---------------------------------------------------------------------------------------
        deleteTestModal: function () {
            AcomModal.open('deleteTestModal');
            $('#pDelId').click($.proxy( this.deleteTest, this));
        },

        // deleteTest()
        // ---------------------------------------------------------------------------------------
        deleteTest: function () {

            var self = this;

            $.ajax({
                url: 'testSettings/' + encodeURIComponent(this.testId),
                dataType: 'json',
                data: {
                    password: $('#pUserPwd').val(),
                    testId: self.testId
                },
                async: false,
                type: 'DELETE',
                success: function (data, textStatus, jqXHR) {
                    Log.info("Successfully deleted test #", self.testId, data, textStatus, jqXHR);
                },
                error: function (jqXHR, textStatus, errorThrow) {
                    Log.error(jqXHR, textStatus, errorThrow);

                    switch (jqXHR.status) {
                        case 401:
                            self.appRouter.navigate("#login", {trigger: true});
                            break;
                        case 404:
                            self.appRouter.navigate("#404", {trigger: true});
                            break;
                        default:
                            self.appRouter.navigate("#serviceUnavailable", {trigger: true});
                    }
                },
                complete: function (jqXHR, textStatus) {
                    $('#pDelId').unbind('click');
                    window.location = window.location.origin + window.location.pathname + window.location.search;
                }
            });
        }
    });
});

これが私のテストケースです:

define([
    'backbone',
    'views/widgets/testSettings/consentSettingsView'
], function (Backbone, ConsentSettingsView) {

    // deleteTestModal()
    // ---------------------------------------------------------------------------------------
    describe('ConsentSettingsView.deleteTest()', function () {

        var server;
        var appRouter;
        var consentSettingsView;

        // Setup
        // -----------------------------------------------------------------------------------------
        beforeEach(function(){

            appRouter = {
                navigate: function () {
                    console.log('navigate called', arguments);
                }
            };

            consentSettingsView = new ConsentSettingsView({
                hasConsented: false,
                testId: 1,
                appRouter: appRouter
            });

            server = sinon.fakeServer.create();

            server.respondWith(/testSettings\/(\d+)/, function(xhr, id) {
                switch (id) {
                    case '1':
                        xhr.respond(200, {'Content-Type': 'application/json'}, JSON.stringify({id: id, success: true}));
                        break;
                    case '2':
                        xhr.respond(401, {'Content-Type': 'application/json'}, JSON.stringify({id: id, success: false}));
                        break;
                    case '3':
                        xhr.respond(404, {'Content-Type': 'application/json'}, JSON.stringify({id: id, success: false}));
                        break;
                    default:
                        xhr.respond(500, {'Content-Type': 'application/json'}, JSON.stringify({id: id, success: false}));
                        break;
                }
            });
        });

        afterEach(function(){

            server.restore();
        });

        it('makes a successful ajax call', function () {

            consentSettingsView.testId = 1;
            consentSettingsView.deleteTest();
        });
    });
});
4

1 に答える 1

0

非同期テストが必要な場合は、非同期テストにジャスミンの正しい方法を使用する必要があります。それらは同期とは異なります。コードを今非同期に変更すると、何も返されず、奇妙な動作が予想されます。

見てみましょう: http://pivotal.github.com/jasmine/#section-Asynchronous_Support

これで、テストは次のようになります。

    it('makes a successful ajax call', function () {
        runs(function() {
            consentSettingsView.testId = 1;
            consentSettingsView.deleteTest();
        });

        var timeoutIn = 1000; // A second
        waitFor(function() {
            // Return something that flags your test is ok or not after the timeout time
        }, 'No server response', timeoutIn);

        runs(function() {
            // Expected result to check from your test
        });
    });

個人的には、この非同期テストを行うより良い方法は、パターンdeleteTestのように引数としてコールバックを渡すことができるようにメソッドを変更することだと思います:promisses

deleteTest: function (success, fail) ....

次に、次のように目的のコンテキストで check と run を入力できます。

if (typeof success === 'function') { success.call(this); }

失敗の場合も同じですが、jQuery オプションからの ajax 失敗コールバック関数内です。

これで、次のようなものをテストに追加できます。

    it('makes a successful ajax call', function () {
        var result = false;
        runs(function() {
            consentSettingsView.testId = 1;
            consentSettingsView.deleteTest(function () { 
                result = true;
            }, function () { 
                result = false; 
            });
        });

        var timeoutIn = 1000; // A second
        waitFor(function() {
            return result;
        }, 'No server response', timeoutIn);

        runs(function() {
            // Expected result to check from your test
            expect(result).toBe(true);
        });
    });

グーグルで探して投稿すると、この記事が見つかりました。

彼は私があなたにしたのと同じように説明します。それがあなたの役に立てば幸いです。

于 2013-01-07T04:51:08.450 に答える