将 TypeMoq 模拟与 Angular TestBed 一起使用

Posted

技术标签:

【中文标题】将 TypeMoq 模拟与 Angular TestBed 一起使用【英文标题】:Using TypeMoq Mock With Angular TestBed 【发布时间】:2017-10-31 12:30:46 【问题描述】:

我已经定义了一个FooService 如下

import Injectable from "@angular/core";
export interface Foo 
    Foo(): string;


@Injectable()
export class FooService implements Foo 
    Foo(): string 
        return "Fooey!";
    

还有一个像这样的BarComponent

import Component from "@angular/core";
import FooService from "./foo.service";

@Component(
    moduleId: 'module.id',
    template: '<h1>Bar Component</h1>'
)
export class BarComponent 
    constructor(private fooService: FooService) 

    doFoo(): string 
        return(this.fooService.Foo());
    

现在我想测试我的BarComponent,我想用TypeMoq模拟FooService,所以我做了以下

import * as TypeMoq from 'typemoq';
import Foo, FooService from "./foo.service";
import TestBed, async from "@angular/core/testing";
import BarComponent from "./bar.component";

describe('BarComponent', () => 
    let component: BarComponent;
    let mockFooService: TypeMoq.IMock<Foo>;

    beforeEach(async(() => 
        mockFooService = TypeMoq.Mock.ofType<Foo>();
        TestBed.configureTestingModule(
            declarations: [BarComponent],
            providers: [ provide: FooService, useValue: mockFooService.object]
        );
    ));

    beforeEach(() => 
        let fixture = TestBed.createComponent(BarComponent);
        component = fixture.componentInstance;
    );

    it('does something', () => 
        mockFooService.setup(x => x.Foo()).returns(() => "FooBar!");
        expect(component.doFoo()).toEqual("FooBar!");
    );

);

但是运行上面会出现以下错误

SyntaxError: Function arg string contains parenthesis
        at new Function (<anonymous>)
        at evalExpression (webpack:///~/@angular/compiler/@angular/compiler.es5.js:25431:25 <- config/karma-test-shim.js:59412:40)
        at jitStatements (webpack:///~/@angular/compiler/@angular/compiler.es5.js:25448:0 <- config/karma-test-shim.js:59429:12)
        at JitCompiler._compileModule (webpack:///~/@angular/compiler/@angular/compiler.es5.js:25658:0 <- config/karma-test-shim.js:59639:35)
        at createResult (webpack:///~/@angular/compiler/@angular/compiler.es5.js:25613:0 <- config/karma-test-shim.js:59594:106)
        at JitCompiler._compileModuleAndAllComponents (webpack:///~/@angular/compiler/@angular/compiler.es5.js:25616:0 <- config/karma-test-shim.js:59597:40)
        at JitCompiler.compileModuleAndAllComponentsSync (webpack:///~/@angular/compiler/@angular/compiler.es5.js:25559:0 <- config/karma-test-shim.js:59540:23)
        at TestingCompilerImpl.compileModuleAndAllComponentsSync (webpack:///~/@angular/compiler/@angular/compiler/testing.es5.js:475:0 <- config/karma-test-shim.js:68201:31)
        at TestBed._initIfNeeded (webpack:///~/@angular/core/@angular/core/testing.es5.js:705:0 <- config/karma-test-shim.js:21376:36)
        at TestBed.createComponent (webpack:///~/@angular/core/@angular/core/testing.es5.js:791:0 <- config/karma-test-shim.js:21462:14)
        at Function.TestBed.createComponent (webpack:///~/@angular/core/@angular/core/testing.es5.js:610:0 <- config/karma-test-shim.js:21281:29)
        at Object.<anonymous> (webpack:///src/app/auth/login/bar.component.spec.ts:19:30 <- config/karma-test-shim.js:99954:41)
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:365:0 <- config/karma-test-shim.js:65763:26)
        at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:79:0 <- config/karma-test-shim.js:65294:39)
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:364:0 <- config/karma-test-shim.js:65762:32)
        at Zone.run (webpack:///~/zone.js/dist/zone.js:125:0 <- config/karma-test-shim.js:65523:43)
        at Object.<anonymous> (webpack:///~/zone.js/dist/jasmine-patch.js:104:0 <- config/karma-test-shim.js:65010:34)
        at webpack:///~/@angular/core/@angular/core/testing.es5.js:96:0 <- config/karma-test-shim.js:20767:17
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:365:0 <- config/karma-test-shim.js:65763:26)
        at AsyncTestZoneSpec.onInvoke (webpack:///~/zone.js/dist/async-test.js:49:0 <- config/karma-test-shim.js:64605:39)
        at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:76:0 <- config/karma-test-shim.js:65291:39)
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:364:0 <- config/karma-test-shim.js:65762:32)
        at Zone.run (webpack:///~/zone.js/dist/zone.js:125:0 <- config/karma-test-shim.js:65523:43)
        at AsyncTestZoneSpec._finishCallback (webpack:///~/@angular/core/@angular/core/testing.es5.js:91:0 <- config/karma-test-shim.js:20762:25)
        at webpack:///~/zone.js/dist/async-test.js:38:0 <- config/karma-test-shim.js:64594:31
        at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:398:0 <- config/karma-test-shim.js:65796:31)
        at Zone.runTask (webpack:///~/zone.js/dist/zone.js:165:0 <- config/karma-test-shim.js:65563:47)
        at ZoneTask.invoke (webpack:///~/zone.js/dist/zone.js:460:0 <- config/karma-test-shim.js:65858:38)
        at timer (webpack:///~/zone.js/dist/zone.js:1732:0 <- config/karma-test-shim.js:67130:29)

是否可以将TypeMoq 与角度TestBed 一起使用,如果可以,您如何正确使用?

【问题讨论】:

【参考方案1】:

我也遇到了这个问题,因为你对供应商的态度。

改变

providers: [ provide: FooService, useValue: mockFooService.object]

providers: [ provide: FooService, useFactory: () =>  return mockFooService.object  ]

使用工厂函数返回为我摆脱了错误。如果你使用 useClass 你会得到一个关于 param.map is not a function 的错误,如果你使用 useValue 你会得到一个关于意外括号的错误。不过,useFactory 和一个返回 moq.object 的内联函数也可以工作。

【讨论】:

这引起了我的注意。为什么我们在使用 useValue 提供程序配置时遇到错误? 当我尝试这样做时,我看到一个错误TypeError: Cannot convert undefined or null to object at Function.getPrototypeOf (native) :-( 我有一个非常相似的设置 我得到的是 SyntaxError: Arg string terminates parameters early,而不是 angular 6(用于 useValue)。也想知道为什么。 @PavelSapehin 我偶然发现了这个罕见的问题,因为在 ES6 类的静态方法的上下文中使用 new this.constructor() 而不是 new this()【参考方案2】:

就我而言,我收到了这个错误。 "Arg 字符串提前终止参数" 。 我做了这样的解决方案。

let params = 
  "NO": 1,
  "ID": 2,
  "FIELD.SECOND": "Test"
;
let text = "$NO test interpolate $ID";

const names = Object.keys(params);
//if you remove this loop you got error
for (let i = 0; i < names.length; i++) 
  names[i] = names[i].split('.').join("")

const vals = Object.values(params);
try 
  console.log(new Function(...names, `return \`$text\`;`)(...vals));
 catch (err) 
  console.error(err);

【讨论】:

以上是关于将 TypeMoq 模拟与 Angular TestBed 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 11 中进行单元测试时,将 json 对象转换为 typescript 接口导致模拟对象出错

模拟指令以测试组件 - Angular 8 与 jasmine 和 Karma

将 Firebase 模拟器与 AngularFire 一起使用

Angular 使用总结路由

单元测试 Angular 5 应用程序的模拟文件列表

Redis篇Redis集群安装与初始