<form id="createWorkout" #cwf="ngForm" (ngSubmit)="showWorkout(skillCountFld)" novalidate> <input name="skillCount" id="skillCount" class="form-control" #skillCountFld="ngModel" ngModel /> <button type="submit" id="buildWorkout">Build a Workout</button> </form>
组件如下:
import { Component, OnInit } from '@angular/core'; import {SkillService} from "../model/skill-service"; import {NgModel} from "@angular/forms"; @Component({ selector: 'app-startworkout', templateUrl: './startworkout.component.html', styleUrls: ['./startworkout.component.css'] }) export class StartworkoutComponent implements OnInit { public skillCount:String; constructor(public skillService:SkillService) { } showWorkout(value:NgModel):void { console.log('breakpoint', value.value); } ngOnInit() { } }
以下是规范:
/* tslint:disable:no-unused-variable */ import {async, ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; import {By, BrowserModule} from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; import { StartworkoutComponent } from './startworkout.component'; import {SkillService} from "../model/skill-service"; import {Store} from "../core/store"; import {SportService} from "../model/sport-service"; import {FormsModule} from "@angular/forms"; import {dispatchEvent} from "@angular/platform-browser/testing/browser_util"; describe('StartworkoutComponent', () => { let component: StartworkoutComponent; let fixture: ComponentFixture; let element:DebugElement; let skillService:SkillService; beforeEach(async(() => { var storeSpy:any = jasmine.createSpyObj('store', ['getValue', 'storeValue', 'removeValue']); var stubSkillService:SkillService = new SkillService(storeSpy); TestBed.configureTestingModule({ declarations: [ StartworkoutComponent ], providers: [{provide:Store , useValue:storeSpy}, SportService, SkillService], imports: [BrowserModule, FormsModule] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(StartworkoutComponent); component = fixture.componentInstance; element = fixture.debugElement; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); describe('without workout', () => { let createWorkout:DebugElement; let skillCount:HTMLInputElement; let submitButton:HTMLButtonElement; beforeEach(() => { createWorkout = element.query(By.css('#createWorkout')); skillCount = element.query(By.css('#skillCount')).nativeElement; submitButton = element.query(By.css('#buildWorkout')).nativeElement; }); it('has createWorkout form', () => { expect(createWorkout).toBeTruthy(); expect(skillCount).toBeTruthy(); }); it('submits the value', fakeAsync(() => { spyOn(component, 'showWorkout').and.callThrough(); tick(); skillCount.value = '10'; dispatchEvent(skillCount, 'input'); fixture.detectChanges(); tick(50); submitButton.click(); fixture.detectChanges(); tick(50); expect(component.showWorkout).toHaveBeenCalledWith('10'); })); }); });
我肯定我错过了一些基本的/简单的东西,但我花了过去一天的时间梳理了所有我能找到的东西,没有运气。
<p>{{cwf.value | json}}</p>
Angular站点上有大量测试成功地设置了此设置,而无需等待何时稳定https://github.com/Angular/Angular/blob/874243279d5fd2bef567a13e0cef8d0cdf68eec1/modules/%40Angular/forms/test/template_integration_spec.ts#l1043
这是因为这些测试中的所有代码都是在fakeasync
区域内执行的,而您在beforeach
内激发fixture.detectChanges();
。因此fakeasync
区域不知道其作用域之外的异步操作。当您调用DetectChanges
时,第一次初始化NGModel
NgModel.prototype.ngOnChanges = function (changes) {
this._checkForErrors();
if (!this._registered)
this._setUpControl(); //<== here
并获取输入事件的正确回调
NgForm.prototype.addControl = function (dir) {
var _this = this;
resolvedPromise.then(function () { // notice async operation
var container = _this._findContainer(dir.path);
dir._control = (container.registerControl(dir.name, dir.control));
setUpControl(dir.control, dir); // <== here
在SetupControl
中,可以看到Input
事件将调用的函数
dir.valueAccessor.registerOnChange(function (newValue) {
dir.viewToModelUpdate(newValue);
control.markAsDirty();
control.setValue(newValue, { emitModelToViewChange: false });
});
1)因此,如果您将fixture.detectchanges
从beforeace
移动到您的测试中,那么它应该可以工作:
it('submits the value', fakeAsync(() => {
spyOn(component, 'showWorkout').and.callThrough();
fixture.detectChanges();
skillCount = element.query(By.css('#skillCount')).nativeElement;
submitButton = element.query(By.css('#buildWorkout')).nativeElement;
tick();
skillCount.value = '10';
dispatchEvent(skillCount, 'input');
fixture.detectChanges();
submitButton.click();
fixture.detectChanges();
expect(component.showWorkout).toHaveBeenCalledWith('10');
}));
但是这个解决方案似乎非常复杂,因为您需要重写代码来移动每个it
语句中的fixture.detectchanges
(skillcount
、submitbutton
等也有问题)
2)正如Dinistro所说的,async
和whenstable
也可以帮助您:
it('submits the value', async(() => {
spyOn(component, 'showWorkout').and.callThrough();
fixture.whenStable().then(() => {
skillCount.value = '10';
dispatchEvent(skillCount, 'input');
fixture.detectChanges();
submitButton.click();
fixture.detectChanges();
expect(component.showWorkout).toHaveBeenCalledWith('10');
})
}));
柱塞实例
但是等等,为什么我们要改变我们的代码?
3)只需将async
添加到beforeEach函数中
beforeEach(async(() => {
fixture = TestBed.createComponent(StartworkoutComponent);
component = fixture.componentInstance;
element = fixture.debugElement;
fixture.detectChanges();
}));
柱塞实例
我试图用Jasmine为Angularjs编写单元测试。这是我的控制器: 和测试 测试失败,即使我试图测试期望(true). toBe(true); 茉莉花,因果报应,棱角分明的嘲弄都在我的索引里。jasmine调试页面中的html,还有测试脚本。 我发现如果删除beforeach()块,expect(true)。托比(真的)通过了。 下面是一个错误:
问题内容: 我一直在努力围绕Jasmine 2.0和AngularJS的承诺。我知道: 茉莉花2.0引入的功能,以取代旧的和功能 在触发摘要循环之前,AngularJS Promise 不会解析 如何在Jasmine 2.0中使用新的异步语法测试AngularJS Promise? 问题答案: 致电后: 致电。这将强制进行摘要循环并传播承诺解决方案 致电。告诉Jasmine异步测试已经完成 这是一
问题 假如你正在使用 CoffeeScript 写一个简单地计算器,并且想要验证其功能是否与预期一致。可以使用 Jasmine 测试框架。 讨论 在使用 Jasmine 测试框架时,你要在一个参数(spec)文档中写测试,文档描述的是代码需要测试的预期功能。 例如,我们希望计算器可以实现加法和减法的功能,并且可以正确进行正数和负数的运算。我们的 spec 文档如下列所示。 # calculator
问题内容: 如何使用AngularJS / karma / jasmine测试来测试API后端? 我试图创建显示我的错误的最小测试用例: echo_server.py 测试/单位/apiSpec.js 输出 问题答案: 提到的测试堆栈不适用于这种方式。由于该请求已装饰在您原始请求的顶部,因此该请求永远不会被分派。 要允许请求通过,您要么需要排除,要么指定某些网址应像这样通过: 在此处阅读文档 另外
我知道在摘要周期中手动调用或会导致$digest已经在进行中错误,但我不知道为什么我在这里得到它。 这是一个包装的服务的单元测试,该服务足够简单,它只是防止对服务器进行重复调用,同时确保试图进行调用的代码仍然获得预期的数据。 单元测试也非常简单,它使用来预期请求。 当调用时出现“$digest ready in progress”错误,这将导致失败。我不知道为什么。我可以通过在这样的超时中包装来解
我接着跑道: 咕噜的因果报应 以运行测试,但它失败,出现以下错误: