Reputation: 11250
The issue I am having, is that each test should be able to be run in any order, however, I want to be able to test different results.
My DataStorageService is a service to extrapolate the storage used. For instance, LocalStorage, NoSQL, etc. could all be used, but my main code will continue to call DAtaStorageService. I simply change the implementation to use whatever module I need or combination of them.
This is a sample block out of test setup.
const BadData:Observable<ITestInterface> = of<ITestInterface>( { Key_: 'Bad', Name: 'Bad Record for Testing' } );
const GoodData:Observable<ITestInterface> = of<ITestInterface>( { Key_: 'Good', Name: 'Good Record for Testing' } );
const NoKey:Observable<ITestInterface> = of<ITestInterface>( { Name: 'Missing Key for Testing' } );
describe('DataStorage Service - Mocked AngularFire Responses', () => {
let ServiceUnderTest:DataStorage<ITestInterface>;
let DependentService:AngularFireDatabase;
const ObjectStub = {
valueChanges: jasmine.createSpy('valueChanges').and.returnValue(GoodData)
};
const AfDbStub = {
object: jasmine.createSpy('object').and.returnValue(ObjectStub)
};
afterEach(() => {
DependentService = null;
ServiceUnderTest = null;
});
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
DataStorage,
{ provide: AngularFireDatabase, useValue:AfDbStub }
]
});
DependentService = TestBed.inject(AngularFireDatabase);
ServiceUnderTest = TestBed.inject(DataStorage);
});
The question I then have, is how to keep setting up the stub to be returned. I am writing tests to handle successful returns, negative returns, etc. However, as I see the building of the stub returns, to return a value, these all seem to be a single style return, unless you configure the first return, the second return, and then the third, etc.
The sample has one service injected, but then it only has a single stub from the AngularFire service for my code to work with. As such, I need to do this complete block for each of the three different tests. Is there a way to do this without 3 different describe blocks? I know I could set this up to get 3 returns for the first call, the second call and then the third call, and each test makes the appropriate number of calls, however this does not feel right.
However, as I want to test success, failure, missing data, the one mock to return the data in the specified order, means my tests have to run in that order, which means they are not truly independent. Is this proper, or do I do something simply like return the different settings, and a test for the negative would make the first call to get a positive result, then the second call in the same test, so it returns the failure and test that result?
EDIT: I also believe my spy/stubs are not set correctly to work with the underlying Angularfire. My question is still on the replacements, but maybe the spys could be set with functions in the return to allow me to check a variable and return good, bad or error?
Upvotes: 2
Views: 1070
Reputation: 2486
I case of testing services I prefer something like this:
{ provide: AngularFireDatabase, useValue: {} } // simple empty object
Then in each test you can use spyOn
function to mock some result, e.g.:
it('success', () => {
spy = jasmine.spyOn(dependentService, 'method').andReturn(42);
expect(service.method()).toEqual(...);
expect(spy).toHaveBeenCalled();
});
In that case you can easily manipulate how depend service should behave in different test scenario.
Upvotes: 2