问题
I'm writing a unit test for a component that makes a call to a service OnInit. If the response is a 'success' one action taken and another for an 'error'.
What is the best way to test both cases? I've created a simplified version of the component and unit test. Something that I could easily test against in both cases.
I've attempted to implement the solution here but I must be off on the implementation. I've also attempted to throw an error as you will see in the spec and comments.
Component
@Component({
selector: 'app-observer-throw-unit-test',
template: '<p>{{ data }}</p>'
})
export class ObserverThrowUnitTestComponent implements OnInit {
public data: string;
constructor(private _observerThrowService: ObserverThrowService) { }
ngOnInit() {
this._observerThrowService.getData().subscribe(
(data) => {
this.data = data;
},
(error) => {
this.redirect()
}
)
}
redirect() {
this.data = "Redirecting...";
}
}
Spec
const data: string = "Lorem ipsum dolor sit amet.";
const ObserverThrowServiceStub = {
error: false,
getData() {
return Observable.create((observer) => {
if(this.error) {
observer.error(new Error());
} else {
observer.next(data);
}
observer.complete();
})
}
}
describe('ObserverThrowUnitTestComponent', () => {
let component: ObserverThrowUnitTestComponent;
let fixture: ComponentFixture<ObserverThrowUnitTestComponent>;
let _observerThrowService: ObserverThrowService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ObserverThrowUnitTestComponent ],
providers: [
{ provide: ObserverThrowService, useValue: ObserverThrowServiceStub },
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ObserverThrowUnitTestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
_observerThrowService = TestBed.get(ObserverThrowService);
});
it('should set "data" to "Lorem ipsum dolor sit amet." on success', () => {
expect(component.data).toEqual("Lorem ipsum dolor sit amet.");
});
it('should set "data" on "Redirecting..." on error',() => {
ObserverThrowServiceStub.error = true;
// spyOn(_observerThrowService, "getData").and.returnValue(Observable.throw("error")); // This did not work and returned : TypeError: undefined is not a constructor (evaluating 'Observable_1.Observable.throw("error")') in src/test.ts
spyOn(_observerThrowService, "getData")
expect(component.data).toEqual("Redirecting...");
});
it('should set "data" on "Redirecting..." on error',() => {
// This works after setting error to true in the previous test
spyOn(_observerThrowService, "getData")
expect(component.data).toEqual("Redirecting...");
});
});
回答1:
I would create two mocks - one that throws an error:
class ObserverThrowServiceStub {
getData() {
return Observable.throw(new Error('Test error'));
}
}
and one that returns successfully.
class ObserverSuccessServiceStub {
getData() {
return Observable.from(data);
}
}
Then, instead of providing the same mock service to all tests, you provide the failing/successful mock service appropriately depending on the test in question (obviously you'll need to move your module configuration into a configurable method that you call from within each test rather than in the .beforeEach()
code.
There is a really nice article on testing Angular services using Observables here (which uses exactly this model): http://www.zackarychapple.guru/angular2/2016/11/25/angular2-testing-services.html
回答2:
someObj.ObservableReturninFunction().subscribe(
(obj)=> {
conosle.log(obj.message);
},
(err)=>{
console.log(err.message);
}
});
when success;
SpyOn(someObj,"ObservableReturninFunction").and.returnValue(
Observable.of({message: "something"}));
when erro:
SpyOn(someObj,"ObservableReturninFunction").and.returnValue(
Observable.throw({message: "some-error"}));
回答3:
You can use Jasmine Spy to spyOn
your mock service class's method which returns an Observable.
More detail is here: Jasmine - how to spyOn instance methods
回答4:
I would add a public error flag in the stub. Then I can create the stub once in beforeEach() and just update the error flag in each test case to decide which version of getData I want to use.
class ObserverServiceStub {
public error = false;
getData() {
if (this.error) {
return Observable.throw(new Error('Test error'));
} else {
return Observable.from(data);
}
}
}
回答5:
install karma-firefox-launcher with
npm install karma-firefox-launcher --save-dev then
karma.config.js file (the only part you will edit is this and leave other content)
plugins: [
require('karma-jasmine'),
require('karma-firefox-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
browsers: ['Firefox']
input only firefox karma.config.js, chrome has issues currently
来源:https://stackoverflow.com/questions/45084568/unit-test-success-and-error-observable-response-in-component-for-angular-2