unit-testing - starter - example angular material projects
Burla ngrx/tienda (3)
Esto es en relación con el lanzamiento oficial de Angular 2. Sé que las pruebas unitarias han cambiado drásticamente entre beta, RC y el lanzamiento oficial.
¿Cuál es una buena forma de simular @ ngrx / store en una prueba unitaria cuando se usa como parámetro en un constructor? No es tan simple como burlarse de un servicio.
Por ejemplo, si quisiera burlarme de un servicio, podría hacer algo como esto:
let serviceStub = { }; // not a true mocked service, just a stub, right?
let de: DebugElement;
let el: HTMLElement;
let nativeEl: Element;
let comp: Typeahead;
let fixture: ComponentFixture<Typeahead>;
describe(''Component:Typeahead'', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [Typeahead],
providers: [
{provide: TypeaheadService, useValue: serviceStub} // provides the service that is being "mocked"
]
}).compileComponents();
fixture = TestBed.createComponent(Typeahead);
nativeEl = fixture.nativeElement;
comp = fixture.componentInstance;
de = fixture.debugElement;
});
});
Y esto funciona
ngrx/store
embargo, para ngrx/store
, no lo hace (si sustituye Store por TypeaheadService). Estoy pensando que tiene que escribir una clase de simulacro que extienda Store, y luego proporcionar eso al componente que se está probando, pero no estoy seguro de por qué ese es el caso (si ese es el caso).
Estoy confundido como la forma de burlarse de ngrx/store
en mis pruebas unitarias y no pude encontrar ninguna documentación en su sitio o github. Quizás lo pasé por alto.
Sí, tienes que burlarse de ngrx/store
, pero no solo de Store. Store espera tres argumentos; uno de tipo Observable y dos de tipo Observer, que es una interfaz. Entonces, probé dos cosas. Pasar valores nulos al constructor StoreMock super()
, pero eso falló en mi afirmación. Mi otra solución fue implementar la interfaz Observer con una clase simulada (observable en este caso). De esta forma podría pasar valores definidos en el constructor de StoreMock.
Esto es solo un ejemplo ilustrativo. El ObservableMock en realidad no se burla de ninguna funcionalidad que estoy tratando de probar en mi aplicación. Está sirviendo como habilitador para que Store se pueda inyectar como proveedor en el Componente que intento probar.
Como Observer es una interfaz, debe implementar sus declaraciones de funciones en el simulacro: next
, error
y complete
.
class ObservableMock implements Observer<any> {
closed?: boolean = false; // inherited from Observer
nextVal: any = ''''; // variable I made up
constructor() {}
next = (value: any): void => { this.nextVal = value; };
error = (err: any): void => { console.error(err); };
complete = (): void => { this.closed = true; }
}
let actionReducer$: ObservableMock = new ObservableMock();
let action$: ObservableMock = new ObservableMock();
let obs$: Observable<any> = new Observable<any>();
class StoreMock extends Store<any> {
constructor() {
super(action$, actionReducer$, obs$);
}
}
Y ahora puede agregar Store como proveedor en el módulo de prueba de su Componente.
describe(''Component:Typeahead'', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [Typeahead],
providers: [
{provide: Store, useClass: StoreMock} // NOTICE useClass instead of useValue
]
}).compileComponents();
});
});
Estoy seguro de que hay otras maneras de hacerlo. Entonces, si alguien tiene alguna otra respuesta, ¡por favor publíquela!
¡Gracias por publicar la pregunta y sugerir una posible solución!
La forma en que me he burlado es usar las acciones reales para establecer un estado inicial, es decir, un estado de burla antes de cada prueba. Aquí hay un ejemplo
beforeEach(inject([Store], (store: Store<ApplicationState>) => {
const someFakeState = {
counter: 9,
counterFilter: ''A_FAKE_COUNTER_FILTER''
};
store.dispatch(new myActionToSetSomeData(someFakeState));
}));
Dentro de su bloque it()
, ahora debería poder verificar que el componente muestre un recuento de 9 y un filtro por ''A_FAKE_COUNTER_FILTER''
.
Por supuesto, puede establecer el estado dentro de su bloque it, en lugar de beforeEach
, siempre y cuando sea antes de la instancia del componente.
Puede usar forRoot
(> = v4) o provideStore
(<= v3) para proporcionar los datos a StoreModule y el resto se hace por usted:
1 - Importarlo:
import { StoreModule } from ''@ngrx/store'';
2 - Crea una simulación de datos:
/*
* Mock data
*/
const PAINTS = [];
3 - Importe en su prueba:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ StoreModule.forRoot(PAINTS) ]
})
}))
En versiones anteriores (antes de v4), debe usar provideStore(PAINTS)
lugar de forRoot(PAINTS)
. Vea el registro de cambios aquí