I have an Angular Service that uses another Service to persist some of its data between page loads:
@Service({providedIn: "root"})
class PersistenceService {
save(key: string, value: string) { ... }
load(key: string): string { ... }
}
@Service({providedIn: "root"})
class DataService {
user?: string;
constructor(private persistence: PersistenceService) {}
init() { this.user = this.persistence.load("user"); }
setUser(str: string) {
this.user = str;
this.persistence.save("user", str);
}
}
When I want to test DataService, I inject a stubbed-out Spy for PersistenceService using the Angular TestBed class:
beforeEach(() => {
fakeValues = {};
persistence = jasmine.createSpyObj("PersistenceService", ["save", "load"]);
persistence.load.and.callFake(key => fakeValues[key]);
TestBed.configureTestingModule({
providers: [
DataService,
{provide: PersistenceService, useValue: persistence},
]
});
instance = TestBed.inject(DataService);
})
I want to test the way that DataService uses persisted values. I can do this easily enough by manipulating the mock PersistenceService (fakeValues in the above example). For example:
it("saves the user", () => {
instance.init();
instance.setUser("Joe");
expect(persistence.save).toHaveBeenCalledWith("user, "Joe");
});
it("loads the user", () => {
fakeValues.user = "Joe";
instance.init();
expect(instance.user).toBe("Joe");
});
I think this might be the wrong way to do this, though, because it requires that I know an implementation detail of DataService: the fact that the user is persisted using the key "user". What I actually want to test is, when I call setUser("Joe"), then reload the page (making a new instance of the DataService), check that instance.user is pulled from the persistence service, and gets set to "Joe".
In the above example, I could of course just call the init method again, or construct a second instance directly with new DataService(TestBed.inject(PersistenceService)), but in my real code, it might be impossible to reset the state of the service instance and re-initialize, and some Services have 4-6 dependencies so constructing one manually is a hassle. It seems like a better pattern would be one where I can inject the service-under-test, make some changes, then simulate a page reload and create a whole new instance, and check its behavior, all in a single test case. Is there an easy way to do that?