在单元测试中模拟带有参数的ngrx存储选择器(角度) [英] Mock ngrx store selectors with parameters in unit tests (Angular)

查看:40
本文介绍了在单元测试中模拟带有参数的ngrx存储选择器(角度)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为Angular中的服务编写单元测试. 我想模拟ngrx的store.select函数,以便测试服务对存储选择器返回的不同值的反应.我希望能够分别模拟每个选择器.

I am trying to write unit tests for a service in Angular. I want to mock the store.select function of ngrx, so I can test how let's say, a service, reacts to different values returned by the store selectors. I want to be able to mock each selector individually.

我的主要问题是如何模拟参数化选择器.

My main problem is how to mock parametrised selectors.

我以前使用过一个BehaviourSubject,它映射到select函数,但这不允许您为不同的选择器返回不同的值.它不可读,因为您在嘲笑哪个选择器并不明显.

I have previously used a BehaviourSubject that I map to the select function, but this doesn't allow you to return different values for different selectors. It is not readable because it is not obvious what selector you are mocking.

选项1:使用主题模拟存储:无法知道主题对应的选择器,无法为不同的选择器返回不同的值.

Opt 1: Mock Store using subject: impossible to know which selector the subject corresponds to, can't return different values for different selectors.

//service.spec.ts

// service.spec.ts

const selectSubject = new BehaviourSubject(null);
class MockStore {
    select = () => selectSubject;
}

选项2:模拟使用储存开关:作品不同的选择,但不能使当所述选择器具有参数它的工作

Opt 2: Mock Store using switch: works for different selectors, but cannot make it work when the selectors have parameters.

//service.spec.ts

// service.spec.ts

    // This works well but how can I make it work with selectors with parameters??
    const firstSubject = new BehaviourSubject(null);
    const secondSubject = new BehaviourSubject(null);
    class MockStore {
        select = (selector) => {
            switch (selector): {
                case FirstSelector: {
                    return firstSubject;
                }
                case SecondSelector: {
                    return secondSubject;
                }
             }
        };
    }

    describe('TestService', () => {
        let service: TestService;
        let store: Store<any>;

        beforeEach(() => {
            TestBed.configureTestingModule({
              providers: [
                TestService,
                { provide: Store, useClass: MockStore }
              ],
            });

            service = TestBed.get(TestService);
            store = TestBed.get(Store);
          });

          it('should do X when first selector returns A and second selector returns B', () => {
            firstSelectorSubject.next(A);
            secondSelectorSubject.next(B);

        // Write expectation
          });
    });

我要模拟的带有参数化选择器的服务方法,因此可以测试具有不同id值的getUserName

Service method with parametrized selector I want to mock, so I can test getUserName with different id values

getUserName(id: string): Observable<string> {
    return this.store.select(getUser(id)).pipe(
      filter(user => user !== null),
      map(user => user.fullName)
    );
  }

推荐答案

NgRx 7.0包括@ ngrx/store/testing,用于模拟Store.有一个overrideSelector方法非常方便.您基本上是在模拟选择器的输出,因此参数无关紧要.

NgRx 7.0 includes @ngrx/store/testing for mocking Store. There is an overrideSelector method that is very handy. You are basically mocking the output of the selector, so the parameters wouldn't matter.

https://medium.com/ngconf/mockstore-in -ngrx-v7-0-f7803708de4e

mockStore.overrideSelector(yourSelector, expectedOutput);

您还可以在MockStore的初始化中设置选择器:

You can also set up the selector in the initialization of the MockStore:

const mockStore = new MockStore<fromState.IState>(
    new MockState(),
    new ActionsSubject(),
    null,
    null,
    [{
        selector: yourSelector,
        value: expectedOutput
    }]
);

如果要实际测试选择器,则应具有专门用于选择器的测试文件.要测试参数化的选择器,您将使用投影仪方法.它接受选择器作用的状态片(或对象)以及任何参数.在我的示例中,我正在测试NgRx实体.

If you want to actually test the selector, you should have a test file specifically for the selector. To test a parameterized selector, you will use the projector method. It takes in the slice of state (or object) that the selector acts on and any parameters. In my example, I am testing an NgRx entity.

selector.ts:

selector.ts:

export const getEntityById: any = createSelector(
    getEntitiesAsDictionary,
    (entities, props) => entities[props.id]
);

spec.ts:

const expectedId = 111;
const expected = { id: expectedId , user: { userId: expectedId } };

const iEntities = { 
    [expectedId ]: expected, 
    [222]: { id: 222, user: { userId: 222 }}, 
    [333]: { id: 333, user: { userId:333 }}
};

const actual = fromState.getEntityById.projector(iEntities, { id: expectedId });

expect(actual).toEqual(expected);

这篇关于在单元测试中模拟带有参数的ngrx存储选择器(角度)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆