亲爱的 stackoverflow 社区,您好,
我们在项目中执行单元测试时遇到了不稳定。我们将不胜感激有关该问题的任何帮助或意见。
问题
do-something.effects.spec.ts
并且do-something.selectors.spec.ts
单元测试在多次执行时似乎会遇到夹具数据冲突。
代码
do-something.selectors.spec.fixture.ts
import { DEFAULT_ROUTER_FEATURENAME, RouterReducerState } from '@ngrx/router-store';
import { IDoSomethingState } from '../../models/do-something-state';
import { Feature } from '../../models/event';
import { Foo } from '../../models/foo';
import * as fromDoSomething from './do-something.reducer';
interface ITestData {
readonly foo: Foo;
}
const testData: ITestData = {
foo: new Foo(
'second'
)
};
export class DoSomethingSelectorsFixture {
state: IDoSomethingState;
getStateForFeature() {
const mockRouterUrl = '/tab2/restore';
return {
[DEFAULT_ROUTER_FEATURENAME]: {
state: {
url: mockRouterUrl
}
} as RouterReducerState,
[Feature.DoSomething]: {
...fromDoSomething.initialState,
[mockRouterUrl]: this.state
}
};
}
setupDoSomethingState() {
this.state = {
foo: testData.foo,
bar: undefined
} as IDoSomethingState;
}
}
do-something.selectors.spec.ts
import { Foo } from '../../models/foo';
import { selectFoo } from './do-something.selectors';
import { DoSomethingSelectorsFixture } from './do-something.selectors.spec.fixture';
describe('DoSomethingFoo Selectors', () => {
describe('select foo', () => {
it('should return foo', () => {
// Arrange
const fixture = new DoSomethingSelectorsFixture();
fixture.setupDoSomethingState();
// Act
const result = selectFoo(fixture.getStateForFeature());
// Assert
expect(result).not.toBeNull();
expect(result).not.toBeUndefined();
expect(result).toEqual(fixture.state.foo as Foo);
});
});
});
do-something.effects.spec.fixture.ts
import { Bar, IBar } from '../../models/bar';
import { Foo } from '../../models/foo';
interface Fixture {
readonly foo: Foo,
readonly bar: IBar
}
export const fixture: Fixture = {
foo: new Foo(
'first'
),
bar: new Bar(
123
)
};
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { DEFAULT_ROUTER_FEATURENAME } from '@ngrx/router-store';
import { TypedAction } from '@ngrx/store/src/models';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { Observable, of } from 'rxjs';
import { DoSomethingApiService } from '../../api/do-something-api.service';
import { Feature } from '../../models/event';
import {
loadBar,
loadBarSuccess,
} from './do-something.actions';
import { DoSomethingEffects } from './do-something.effects';
import { fixture } from './do-something.effects.spec.fixture';
import {
selectFoo
} from './do-something.selectors';
describe('DoSomethingFooEffects', () => {
let actions$: Observable<TypedAction<string>>;
let effects: DoSomethingEffects;
let store: MockStore;
let apiService: DoSomethingApiService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{
path: 'tab2',
children: []
}
])
],
providers: [
DoSomethingEffects,
provideMockActions(() => actions$),
provideMockStore({
initialState: {
[DEFAULT_ROUTER_FEATURENAME]: {
state: {
url: '/myUrl',
},
},
[Feature.DoSomething]: {
['/myUrl']: undefined
}
},
}),
{
provide: DoSomethingApiService,
useFactory: (): Partial<DoSomethingApiService> => ({
getBarOfFoo: () => of(undefined)
}),
}
],
});
effects = TestBed.inject(DoSomethingEffects);
store = TestBed.inject(MockStore);
apiService = TestBed.inject(DoSomethingApiService);
});
describe('loadBarOfFoo', () => {
it('should return loadBarOfFooSuccess on success', async () => {
// Arrange
store.overrideSelector(selectFoo, fixture.foo);
spyOn(
apiService,
'getBarOfFoo'
).and.returnValue(of(fixture.bar));
actions$ = of(
loadBar({ url: 'test' })
);
// Act
const output =
await effects.loadBarOfFoo$.toPromise();
// Assert
expect(output).toEqual(
loadBarSuccess({
url: '/myUrl',
bar: fixture.bar,
})
);
});
});
});
Karma 单元测试日志输出
Chrome Headless 98.0.4758.109 (Mac OS 10.15.7): Executed 0 of 2 SUCCESS (0
Chrome Headless 98.0.4758.109 (Mac OS 10.15.7): Executed 1 of 2 SUCCESS (0
Chrome Headless 98.0.4758.109 (Mac OS 10.15.7) DoSomethingFoo Selectors select foo should return foo FAILED
Error: Expected $.name = 'first' to equal 'second'.
at <Jasmine>
at UserContext.<anonymous> (src/app/features/do-something/do-something.selectors.spec.ts:19:22)
at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:400:1)
at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/zone-testing.js:301:43)
Chrome Headless 98.0.4758.109 (Mac OS 10.15.7): Executed 2 of 2 (1 FAILED) (0 secs / 0.055 secs)
Chrome Headless 98.0.4758.109 (Mac OS 10.15.7) DoSomethingFoo Selectors select foo should return foo FAILED
Error: Expected $.name = 'first' to equal 'second'.
at <Jasmine>
at UserContext.<anonymous> (src/app/features/do-something/do-something.selectors.spec.ts:19:22)
at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:400:1)
at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/zone-testi
Chrome Headless 98.0.4758.109 (Mac OS 10.15.7): Executed 2 of 2 (1 FAILED) (0.072 secs / 0.055 secs)
TOTAL: 1 FAILED, 1 SUCCESS
TOTAL: 1 FAILED, 1 SUCCESS
存储库
https://github.com/Olddude/flaky-selector-tests