【问题标题】:Angular 6 & Electron: Using a mocked class for unit testing and extend the real class does not workAngular 6 & Electron:使用模拟类进行单元测试并扩展真实类不起作用
【发布时间】:2019-03-07 13:40:03
【问题描述】:

我尝试使用 jasmine 和 angular 6 在我的电子应用程序中编写单元测试,但这种方式不起作用。我有一项服务,在我对另一项服务的特定测试中不需要测试。所以我决定像这样模拟第一个服务:

import { Injectable } from '@angular/core';
import { TestService } from '../../services/test/test.service';

@Injectable()
export class TestServiceMock extends TestService {

    private somePath: string;

    public isFileExistent(path: string): boolean {
        return path === '\\some\\kind\\of\\path\\some.json' ? true : false;
    }
}

我在 Visual Studio 代码中收到以下错误:

[ts] Class 'TestServiceMock' incorrectly extends base class 'TestService'.
Types have separate declarations of a private property 'somePath'.

我想我知道会发生这个错误,因为“somePath”成员与“TestService”中的成员有些不同,但它确实不是(在我的理解中)!这是“TestService”:

import {Injectable} from '@angular/core';
import {ElectronService} from '../electron/electron.service';

@Injectable()
export class TestService {

    private somePath: string;

    constructor(private electron: ElectronService) {
        this.somePath = this.electron.remote.app.getAppPath();
    }

    public isFileExistent(path: string): boolean {
        return // some boolean after a lot of operations not needed here
    }
}

最后但并非最不重要的是我正在编写的测试显示以下错误:

[ts] Type 'typeof TestServiceMock' cannot be converted to type 'TestService'.
Property 'somePath' is missing in type 'typeof TestServiceMock'.

还有测试:

import { RealService } from './real.service';
import { TestServiceMock } from '../../response-models/test/test.service.mock';
import { TestService } from '../../services/test/test.service';

describe('RealService:', () => {
    let realservice: RealService;

    beforeEach(() => {
        realservice = new RealService(TestServiceMock as TestService);
    });

    it('should be available:', () => {
        expect(realservice).toBeDefined();
    });
});

提前感谢您的帮助!

【问题讨论】:

    标签: angular typescript unit-testing jasmine electron


    【解决方案1】:

    您的模拟服务不需要扩展真实服务。你可以有这样的东西:

    export class TestServiceMock {
      public isFileExistent(path: string): boolean {
        return true;
      }
    }
    

    这定义了外部代码可以与之交互的所有公共方法/字段,并且在测试的情况下期望找到。

    然后在您的测试文件中将以下内容添加到 angular 默认提供的 beforEach 块中:

    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      providers: [
        {provide: TestService, useValue: new TestServiceMock()} // <- this is what you need
      ]
    }).compileComponents();
    

    注释中标有箭头的那一行本质上说提供TestService,但实际上使用了这个值。这样,期望接收 TestService 的组件会得到它,但不是真正的。

    使用TestBed,您可以获取您注入的TestService(这是假的)的句柄,并对其应用间谍以操纵其方法的输出。

    希望对你有帮助。

    【讨论】:

    • 在摆弄了一下之后,这个解决方案对我来说效果很好!非常感谢!
    【解决方案2】:

    The answer by @M Mansour 很适合这个问题。

    但是,如果您想在不使用 TestBed 的情况下测试此单元,您可以为您的类提供由 jasmine.createSpyObj() 创建的 spy 对象或一个真实对象,然后是您想要模拟的 spyOn 函数。

    使用实物然后窥探函数的示例:

    import { RealService } from './real.service';
    import { TestService } from '../../services/test/test.service';
    
    describe('RealService:', () => {
      let realService: RealService;
      let testService: TestService;
    
      beforeEach(() => {
        testService = new TestService();
        realService = new RealService(TestService);
      });
    
      it('should call isFileExistent with valid path', () => {
        spyOn(testService, 'isFileExistent').and.returnValue(true);
        realService.doSomething();
        expect(testService.isFileExistent).toHaveBeenCalledWith('VALID_PATH');
      });
    });
    

    当然,这样做可能会导致您在目标单元之上创建所有依赖项。但我发现它运行起来更快,也更容易理解。

    【讨论】:

      猜你喜欢
      • 2015-12-25
      • 1970-01-01
      • 2013-07-08
      • 1970-01-01
      • 2012-11-14
      • 2018-11-11
      • 1970-01-01
      • 2015-05-05
      • 1970-01-01
      相关资源
      最近更新 更多