Angular 4单元测试与jasmine / karma与http post mocking - 如何修复

时间:2017-09-26 07:49:39

标签: angular unit-testing typescript jasmine karma-jasmine

我有一项服务,我想在角4打字茉莉花中进行单元测试。

现在,http正在执行post,但它会返回一个标识,但是它没有发送任何内容。

我想要有良好的代码覆盖率,但我不明白如何完成这个嘲弄声明。

此处是我的服务文件中http post的方法

addSession() {
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });

        return this.http.post(this.url, JSON.stringify({}), options)
            .map((response: Response) => response.json());

}

然后是SPEC FILE ,我没有得到真正的测试内容,我想假设我从服务http帖子收到了一个号码,响应应该是{{ {1}}

规格

000000014

4 个答案:

答案 0 :(得分:6)

为了达到你想要的效果,你需要的模拟是一个简单的函数,返回与POST正常相同的函数;另一件事是你的测试不应该是真正的服务器,所以你需要这样的东西(你可能需要添加其他依赖项):

import { HttpModule } from '@angular/http';
import { TrackerFormService } from './tracker-form.service'
import { Observable } from 'rxjs/Observable'

describe('TrackerFormService', () => {
// Mock the service like this and add all the functions you have in this fashion
let trackerFormService: TrackerFormService,
  mockService = {
    addSession: jasmine.createSpy('addSession').and.returnValue(Observable.of('your session object mock goes here'))
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpModule],
      providers: [{
        provide: TrackerFormService,
        useValue: mockService
      }]
    });
  });

  // Do this trick to inject the service every time, and just use `service` in your tests
  beforeEach(inject([TrackerFormService], (trackerFormService) => {
    service = trackerFormService;
  }));

  describe('addSession', () => {
    it('add session ', () => {
      let fakeResponse = null;

      // Call the service function and subscribe to it to catch the fake response coming from the mock.
      service.addSession().subscribe((value) => {
        // in here value will be whatever you put as returnValue (remember to keep the observable.of())
        fakeResponse = value;
      });

      // expects as in any test.
      expect(fakeResponse).toBeDefined();
      expect(fakeResponse).toBe('your session object mock goes here');
    });
  });
});

答案 1 :(得分:0)

使用Angular 4.3,HttpClient服务取代了Http,并提供了一种模拟HTTP请求的简便方法。它在官方页面上有详细记录:https://angular.io/guide/http

答案 2 :(得分:0)

你设置测试/模拟的方式,你可以伪造回调,并检查你得到了你期望的结果。通过这样做,您将测试模拟响应将由map语句正确转换。有了你的间谍,你还可以检查post方法的调用方式。这将检查选项是否符合您的预期。

但在我看来,这是一个相当复杂的解决方案。我倾向于通过拆分方法来避免模拟和间谍,所以每种方法都只做一件事。因为你的addSession方法目前正在做三件不同的(但依赖于逻辑的)事情:

  1. 为addSession xhr调用创建选项
  2. 执行通话
  3. 转换回复
  4. 如果你在三个方法中打破方法,你可以在单独的测试中轻松测试方法#1和#3,方法#2只包含对http库的调用。这使您可以在不调用http库的情况下获得与上述相同的测试值。

    现在方法#2怎么样......它还没有经过测试,我认为没有理由对它进行测试。因为你没有写那段代码。此外,如果您使用angulars http模块,我相信他们自己也有可靠的单元测试。

    您的服务响应应该已经包含在额外的集成测试中,运行频率较低,检查服务api仍然会返回您期望的内容。

    如果您真的希望代码覆盖率中有一行绿色,那么您可以选择使用名为nock的库。 Nock将拦截您的应用程序将导致的所有xhr流量。在测试文件中,您可以使用nock对象将xhr请求映射到模拟响应。

    
    
    var scope = nock('http://myapp.iriscouch.com')
                    .post('/users', {
                      username: 'pgte',
                      email: 'pedro.teixeira@gmail.com'
                    })
                    .reply(201, {
                      ok: true,
                      id: '123ABC',
                      rev: '946B7D1C'
                    });
    
    
    

    复制自:https://www.npmjs.com/package/nock

    有关一般测试的参考和其他信息以及我建议观看测试的数量 "预算现实"作者Justin Searls

答案 3 :(得分:-2)

http服务请求的示例测试用例

describe('Forgot Password Controller', function () {
    var $controller,
        $httpBackend,
        $q,
        $rootScope,
        $state,
        controller,
        scope,
        accountProvider;

    beforeEach(module('app'));
    beforeEach(inject(function (_$injector_, _$controller_, _$rootScope_) {

        $controller = _$controller_;
        $rootScope = _$rootScope_;
        $httpBackend = _$injector_.get('$httpBackend');
        $state = _$injector_.get('$state');
        $q = _$injector_.get('$q');
        accountProvider = _$injector_.get('accountProvider');
        scope = _$rootScope_.$new();

        controller = $controller(app.controllers.forgotPassword, {
            $state: $state,
            accountProvider: accountProvider
        });
    }));

    afterEach(function () {
        $httpBackend.verifyNoOutstandingRequest();
        $httpBackend.verifyNoOutstandingExpectation();
    });

    describe('forgot password submission', function () {

        it('Can submit a forgot password request successfully', function () {
            $httpBackend.expectPOST("URL DOMAIN" + '/events/requestPasswordReset').respond(200);
            spyOn($state, 'go');
            controller.form = { emailAddress: 'aks@gmail.com' };

            controller.submit();

            expect(controller.submitting).toBe(true);

            $httpBackend.flush();

            expect(controller.submitting).toBe(false);
            expect($state.go).toHaveBeenCalledWith('login', { successMessage: 'An email sent to ' + controller.form.emailAddress + ' contains instructions for resetting your password.' });
        });

        it('Can handle when a user is not found when submitting a forgot password request', function () {
            $httpBackend.expectPOST(app.env.EDGE_SERVICE_PATH + '/events/requestPasswordReset').respond(404);
            spyOn($state, 'go');
            controller.form = { emailAddress: 'aks@gmail.com' };

            controller.submit();

            expect(controller.submitting).toBe(true);
            $httpBackend.flush();

            // We intentionally want to make it appear to the user that the password reset email was sent even when a user
            // does not exist, to help hide info about which users exist in the system
            expect(controller.submitting).toBe(false);
            expect($state.go).toHaveBeenCalledWith('login', { successMessage: 'An email sent to ' + controller.form.emailAddress + ' contains instructions for resetting your password.' });

        });

        it('Can handle unexpected errors from submitting a forgot password request', function () {
            $httpBackend.expectPOST("URL DOMAIN"  + '/events/requestPasswordReset').respond(500);

            controller.submit();
            $httpBackend.flush();

            expect(controller.errors.unexpectedError).toBe(true);
        });

        it('Can handle 422 validation errors from submitting a forgot password request', function () {
            var responseData = {
                fieldErrors: {
                    username: [{code: 'error'}, {code: 'required', message: 'This is required.'}]
                }
            };
            $httpBackend.expectPOST("URL DOMAIN" + '/events/requestPasswordReset').respond(422, responseData);

            controller.submit();
            $httpBackend.flush();

            expect(controller.errors.validationErrors).toBe(true);
            expect(controller.errors.fieldErrors).toEqual(responseData.fieldErrors);
        });

        it('Can handle 503 service unavailable from submitting a forgot password request', function () {
            $httpBackend.expectPOST("URL DOMAIN" + '/events/requestPasswordReset').respond(503);

            controller.submit();
            $httpBackend.flush();

            expect(controller.errors.serviceUnavailable).toBe(true);
        });

    });

});