Unknown developer
Unknown developer

Reputation: 5920

Angular unit testing a service

I am struggling to test a simple service. I cannot find out what exactly to test.

@Injectable()
export class MyService {
    constructor(
        private firstService: FirstService,
        private secondService: SecondService) {
    }

    deals(body: myModel): Observable<any> {
        let url = this.secondService.makeUrl('/api/deals');
        return this.firstService.post(url, body);
    }

}

myModel is like:

export class myModel {
    meta: otherModel;
    data: any;
}  

this.secondService.makeUrl() returns a url and this.firstService.post() is actually an http.post request.

The problem is I do not know how to test deals method. I have mocked FirstService and SecondService e.g.

mockFirstService = jasmine.createSpyObj(["post"]);

everything is okay inside beforeEach (TestBed.configureTestingModule etc), but I do not know what exactly to add inside

 it(...)

What exactly do I have to test and how?

Upvotes: 0

Views: 53

Answers (1)

dmcgrandle
dmcgrandle

Reputation: 6060

If I were looking to test the deals method in 'MyService' as detailed in your question, I would mock and spyon the two dependencies, as you mentioned, and then change the results from those dependencies and be sure all the test cases you want to account for are working. Since you don't have any error checking, I wouldn't test for that - though you do want to error check somewhere, perhaps in the services. I see at least three tests I would do: check the call and arguments sent to FirstService, check the call to SecondService, and check the return Observable.

I have set up a test stackblitz to demonstrate here: https://stackblitz.com/edit/stackoverflow-q-53102348?file=app%2Fmy.service.spec.ts

Here is the MyService describe from that stackblitz:

describe('MyService', () => {
    let myService: MyService;
    let mockFirstService = jasmine.createSpyObj('FirstService', {
        post: of({results: 'Ok'})
    });
    let mockSecondService = jasmine.createSpyObj('SecondService', {
        makeUrl: '/api/deals'
    });

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [/* any imports needed */],
            providers: [MyService,
            { provide: FirstService, useValue: mockFirstService }, 
            { provide: SecondService, useValue: mockSecondService }
            ]
        });
        myService = TestBed.get(MyService);
    });

    it('should be createable', () => {
        expect(myService).toBeTruthy();
    });
    describe('deals() method', () => {
        const testData: myModel = { meta: {}, data: 'test' };

        it('should call secondService.makeUrl()', () => {
            myService.deals(testData);
            expect(mockSecondService.makeUrl).toHaveBeenCalled();
        });
        it('should call firstService.post() with an url and a myModel', () => {
            myService.deals(testData);
            expect(mockFirstService.post).toHaveBeenCalledWith('/api/deals', testData);
        });
        it('should return an Observable that resolves properly', () => {
            mockFirstService.post.and.returnValue(of({results: 'Good'})); // Change return
            myService.deals(testData).subscribe(data => {
                expect(data).toEqual({results: 'Good'});
            })
        });

    });
});

Upvotes: 1

Related Questions