Angular 4 test units with jasmine / karma with http post mocking - how to fix

I have a service, I want unit test in angular 4 typescript jasmine.

Now http does post and it returns an identifier, however .. it does not send anything.

I just want to have good code, but I don’t understand how to complete this mocking instruction completely.

here is the method for http post in my service file

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

Then the SPEC FILE , which I do not get what to really test, I assume that pretending that I received the number from the service mail message, the answer should be something like 000000014

Spec

 import { TrackerFormService } from './tracker-form.service' import { Observable } from 'rxjs/Observable' describe('TrackerFormService', () => { let trackerFormService: TrackerFormService, mockHttp; beforeEach(() => { mockHttp = jasmine.createSpyObj('mockHttp', ['get', 'post', 'put'] ) trackerFormService = new TrackerFormService(mockHttp); }); describe('addSession', () => { it('add session ', () => { // how to test, what to test? // response , is a number? how to mock/fake this? }) }) }) 
+5
source share
4 answers

To achieve what you want, the layout you need is a simple function that returns the same as POST. Another thing is that your test should not really hit the server, so you will need something like this (you may need to add other dependencies):

 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'); }); }); }); 
+2
source

With Angular 4.3, the HttpClient service is introduced, which replaces Http and provides an easier way to mock HTTP requests. It is well documented on the official page: https://angular.io/guide/http

0
source

Test Case Example for HTTP Service Requests

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

Well, as you set up the test / layout, you can fake a mail call return and verify that you get the expected result. By doing so, you will verify that the laughed answer will be correctly converted to your map operator. With your spy, you can also check how the post method was called. This will check if the parameters match what you expect.

But, in my opinion, this is a rather complicated decision. I would prefer to avoid bullying and spyware by splitting the method so that each method just does one thing. Since your addSession method currently does three different (but logically dependent) things:

  • create parameters to call addSession xhr
  • makes a call
  • convert answer

If you break the method down to three, you can easily test method # 1 and # 3 in separate tests, and method # 2 will only contain the http library call. This allows you to achieve the same test value as above without calling the http library.

Now what about method number 2 ... it is still untested and, in my opinion, there is no reason to test it at all. Because you are not writing this code. Also, if you use the HTTP corner module, I am sure that they have robust unit tests.

Your service response should already be covered by an additional integration test, less often checking that the api service will still return what you expect.

If you really want one line to be green in your code coverage, then you could use a library called nock. Nock will intercept all xhr traffic generated by your application. In the test file, you can match xhr requests to make fun of the answers with a nock object.

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

copied from: https://www.npmjs.com/package/nock

For help and additional information on testing in general and how much you need to check, I recommend watching Justin Searle's "Budget Reputation"

0
source

Source: https://habr.com/ru/post/1272116/


All Articles