简体   繁体   English

在Angular(7+)中测试可选的构造函数参数

[英]Test optional constructor parameter in Angular (7+)

I have a problem and would appreciate a helping hand. 我有问题,将不胜感激。

We have a service with a constructor using optional params like so 我们有一个带有构造函数的服务,该构造函数使用可选的参数,例如

@Injectable()
export class OurService {
    constructor(
        private someService: SomeService,
        @Optional() someOption: SomeOption,
    ) {
        if(someOption) {
            this.someService.doSomethingWith(someOption);
        }
        // ...do other things
    }
    // ...other methods
}

Now I want to test that and get good coverage which means there need to be tests where OurService gets instantiated one time with, the other time without someOption and also I want to expect that someService.doSoemthingWith has been called. 现在,我想测试一下并获得良好的覆盖,这意味着需要进行一些测试,其中OurService一次实例化,另一次没有someOption实例化,而且我希望可以调用someService.doSoemthingWith。

I usually setup my testing-module like so 我通常像这样设置我的测试模块

let service: OurService;
let someService: SomeService;

beforeEach(async(() => {
    TestBed.configureTestingModule({
        imports: [],
        declarations: [],
        providers: [
            { provide: SomeService, useClass: MockSomeService },
        ],
    }).compileComponents();
}));

beforeEach(() => {
    service = TestBed.get(AuthService);
    someService = TestBed.get(SomeService);
});

Now I have strong difficulty trying to get all my tests right. 现在,我很难尝试正确完成所有测试。 How do I test these 3 things? 我该如何测试这三件事?

  • should call someService when someOption was provided 提供someOption时应调用someService
  • should not call someService when someOption was not provided 未提供someOption时不应调用someService
  • should test the other things regardless 应该测试其他东西

Here my attempts (among heaps of others..): 这是我的尝试(在其他尝试中):

  1. install a spy and see if method has been called 安装间谍并查看是否已调用方法

     it('blabla', () => { spyOn(someService, 'doSomethingWith'); // I guess the spy is too late because TestBed get already called the constructor expect(someService.doSomethingWith).toHaveBeenCalled(); }); 
  2. attempt to add a provider for this one test 尝试为此测试添加提供程序

     it('blabla', () => { spyOn(someService, 'doSomethingWith'); TestBed.overrideProvider(SomeOption, { useValue: MockSomeOption }); // MockSomeOption is defined somewhere TestBed.compileComponents(); service = TestBed.get(SomeService); // does not work expect(someService.doSomethingWith).toHaveBeenCalled(); }); 
  3. inject smeOption (dont know how, hence this code is wic) 注入smeOption(不知道如何,因此此代码是正确的)

     it('blabla', inject([SomeService], (someService: SomeService) => { //const injector = Injector.create({ providers: [{ provide: SomeOption, useValue: MockSomeOption }] }); spyOn(someService, 'doSomethingWith'); // ?? what now ?? expect(someService.doSomethingWith).toHaveBeenCalled(); }); 
  4. Add someOption to the TestBed setup like so 像这样将一些选项添加到TestBed设置

     beforeEach(async(() => { TestBed.configureTestingModule({ imports: [], declarations: [], providers: [ { provide: SomeService, useClass: MockSomeService }, { provide: SomeOption, useClass: MockSomeOption }, ], }).compileComponents(); })); // problem now is that it is always provided. and I can not test the else-path 

How can I set up my service once as required by most tests, and then add the someOption in one test and call the constructor again so that my spy can do its secret espionage job? 如何按大多数测试的要求设置一次服务,然后在一个测试中添加someOption并再次调用构造函数,以便我的间谍可以执行其秘密间谍活动?

I'm not sure if it is exactly what you want but you can nest describe ... 我不确定这是否正是您想要的,但是您可以嵌套describe ...

describe('Our Service Tests', () => {

    describe('Given an optional parameter', () => {
        beforeEach(async(() => {
            TestBed.configureTestingModule({
                imports: [],
                declarations: [],
                providers: [
                    { provide: SomeService, useClass: MockSomeService },
                    { provide: SomeOption, useClass: MockSomeOption },
                ],
           }).compileComponents();
        }));

        // Tests with the optional parameters
    });

    describe('Given no optional parameter', () => {
        beforeEach(async(() => {
            TestBed.configureTestingModule({
                imports: [],
                declarations: [],
                providers: [
                    { provide: SomeService, useClass: MockSomeService },
                ],
            }).compileComponents();
        }));

        // Tests not using the optional parameter
    });

});

If I only have one or two tests that require a unique setup I'll usually skip creating a describe for those tests. 如果我只有一个或两个需要独特设置的测试,我通常会跳过为这些测试创建描述的过程。 Instead I'll create one nested describe with a default setup for the majority of tests and then just add the unique tests to the outer describe and have them each do their own setup. 相反,我将为大多数测试创建一个带有默认设置的嵌套描述,然后将唯一的测试添加到外部描述中,并使它们各自进行自己的设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM