在上一篇文章中,我们介绍了 Angular 单元测试的基础知识,本文开始介绍如何对 Angular 的主要元件进行单元测试。
我们在使用 Angular CLI 创建项目时,会自动为 AppComponent 创建一个单元测试文件 app.component.spec.ts. 单元测试文件的名字以 .spec.ts 结尾,是一种约定,并且与被测试组件位于同一个路径中。
接下来,我们就对 app.component.spec.ts 进行研究,初步学习如何测试一个组件。 app.component.spec.ts 文件内容如下:
import { TestBed } from '@angular/core/testing’;
import { AppComponent } from './app.component’;
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'my-app-unittest'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('my-app-unittest’);
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('my-app-unittest app is running!’);
});
});
在文件的开头,是一个 beforeEach 初始化函数,完成测试前的准备工作。在 beforeEach 方法中,调用了 TestBed 类的 configureTestingModule 方法配置组件所在的模块。configureTestingModule 方法接收一个对象参数,而对象参数的值与模块的 @NgModule 装饰器的值相同。在这里,我们传入的是 declarations 数组,包含了 AppComponent 组件。完成模块配置后,调用 compileComponents 完成测试模块的构建。一旦构建成功,AppComponent 组件就属于该测试模块了。
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
在第一个单元测试用例中,使用 createComponent 方法创建了一个 AppComponent 组件装置类的对象。该对象是一个 ComponentFixture 类的实例,泛型的类型值是 AppComponent.
ComponentFixture 类专门用于组件的调试和测试,定义如下:
class ComponentFixture<T> {
constructor(componentRef: ComponentRef<T>, ngZone: NgZone, _autoDetect: boolean)
debugElement: DebugElement
componentInstance: T
nativeElement: any
elementRef: ElementRef
changeDetectorRef: ChangeDetectorRef
componentRef: ComponentRef<T>
ngZone: NgZone | null
detectChanges(checkNoChanges: boolean = true): void
checkNoChanges(): void
autoDetectChanges(autoDetect: boolean = true)
isStable(): boolean
whenStable(): Promise<any>
whenRenderingDone(): Promise<any>
destroy(): void
}
在组件装置类的对象创建成功后,可以通过 componentInstance 属性,获得 AppComponent 组件类的实例。
最后,我们使用 toBeTruthy 匹配函数,验证 AppComponent 实例是否有效。
it(`should have as title 'my-app-unittest'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('my-app-unittest’);
});
在第二个单元测试用例中,对应用对标题属性的值进行了验证。因为我们已经获得了 AppComponent 实例,就可以对他的公共属性和方法进行测试。在单元测试用例中,我们使用 toEqual 方法验证 title 属性对值。
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('my-app-unittest app is running!’);
});
在第三个单元测试用例中,对页面上渲染的文字进行了验证。因为组件不只包含类文件,还包含模板文件,所以也需要对类和模板对交互,或者说绑定关系,进行测试,才能保证测试更充分。
我们先调用了 ComponentFixture 类的 detectChanges 方法,目的是触发组件的变化检测机制,强制更新绑定的数据。然后,再使用组件的 nativeElement 属性,查找绑定数据的 DOM 元素,最后,验证 DOM 元素的 textContent 是否与绑定的数据相同。
在项目所在的路径下,打开一个命令行,运行测试命令:
ng test
你会看到测试引擎开始执行单元测试用例,并打开一个浏览器,展示测试结果。

很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
我有:When/^(?:|I)follow"([^"]*)"(?:within"([^"]*)")?$/do|link,selector|with_scope(selector)doclick_link(link)endend我打电话的地方:Background:GivenIamanexistingadminuserWhenIfollow"CLIENTS"我的HTML是这样的:CLIENTS我一直收到这个错误:.F-.F--U-----U(::)failedsteps(::)nolinkwithtitle,idortext'CLIENTS'found(Capybara::Element