骆金凤 發表於 2019-9-30 10:55:00

angular单元测试学习(jasmine)

<p>单元测试简介:https://segmentfault.com/a/1190000009737186</p>
<p>单元测试-Jasmine:https://segmentfault.com/a/1190000009737204</p>
<p>angular2单元测试:https://segmentfault.com/a/1190000009769787#articleHeader1</p>
<p>&nbsp;</p>
<h1>概念简介</h1>
<h3>Jasmine&nbsp;</h3>
<p>Jasmine测试框架提供了编写测试脚本的工具集,而且非常优秀的语义化,让测试代码看起来像是在读一段话。</p>
<p>describe,beforeEach,it,expect等方法,利用这些方法可以定义单元测试如何执行,单元测试的结果和预期。</p>
<p>官方文档:https://jasmine.github.io/api/edge/global.html#expect</p>
<h3>Karma</h3>
<p>有Jasmine测试脚本,还需要Karma来帮忙管理这些脚本,以便于在浏览器中运行,可以理解Karma为运行这些测试脚本的容器。</p>
<p>需要在根目录创建 karma.conf.js 文件,这相当于一些约定。文件是为了告知karma需要启用哪些插件、加载哪些测试脚本、需要哪些测试浏览器环境、测试报告通知方式、日志等等。</p>
<p>官方文档:https://karma-runner.github.io/1.0/config/configuration-file.html</p>
<h3>Angular测试工具集</h3>
<p>testded</p>
<p>testded是angular提供用于单元测试的主要工具方法。为单元测试配置和初始化环境,提供创建组件和服务的方法。</p>
<p>还有spy和一些异步支持</p>
<p>&nbsp;</p>
<h1>结合Jasmine和Angular测试工具集编写单元测试案例</h1>
<p><strong>Jasmine单元测试的基础概念</strong></p>
<p>Jasmine中的单元测试有几个概念:test suit、Specs、Expectations</p>
<p><strong>test suit 测试套件</strong></p>
<p>可以理解为一组单元测试用例的集合。Jasmine用describe函数来表示</p>
<p id="articleHeader2"><strong>Specs&nbsp;测试案例</strong></p>
<p>一个单元测试用例,Jasmine使用函数it来表示</p>
<p><strong>Expectations 期望值</strong></p>
<p>一个单元测试用例执行后,对执行结果的期待,Jasmine使用函数expect来表示</p>
<p>&nbsp;</p>
<h3>Jasmine单元测试常用方法</h3>
<p><strong>Matchers</strong>:对期待值进行判断,toBeTruthy,toBeNull这种,也可以自己实现Matcher</p>
<p><strong>Setup 与 Teardown</strong>:在测试套件中,一些重复的代码可以放在setup和teardown中。setup(对应beforeEach)为每一个单元测试案例执行之前会执行,Teardown(对应afterEach)为每一个单元测试案例执行之后会执行,</p>
<p><strong>数据共享</strong>:在describe 来定义相应的变量,这样每个 it 内部可以共享它们</p>
<p><strong>spy</strong>: 文档翻译:https://blog.csdn.net/GuoJiangweigege/article/details/52130589&nbsp; 并参照:https://www.cnblogs.com/laixiangran/p/5060922.html</p>
<p>spyOn(object, "methodNam");//在object对象上添加methodNam,当调用object对象上的方法,为模拟调用,不会执行methodNam方法的代码。spyOn写在beforEach或者it中,每一个测试案例执行完之后,被销毁。</p>
<p>spyOn(object, "methodNam").and.callThrough();//methodNam方法的代码会被执行</p>
<p>spyOn(object, "methodNam").and.callFake(fn);//methodNam方法会被fn替代,执行fn</p>
<p>spyOn(object, "methodNam").and.returnValue(value);//methodNam的返回值为value</p>
<p>&nbsp;</p>
<h3 id="articleHeader10">Angular工具集</h3>
<p><strong>TestBed</strong></p>
<p>如官方所说,是angular单元测试最主要的api。个人理解是一组单元测试的测试context,按配置生成模块、组件,然后提供这些模块或者组件用于单元测试。</p>
<p>1 TestBed创建模块:TestBed.configureTestingModule</p>
<p>构建一个angular模块,并返回,接受参数用于配置模块,和@NgModule的配置无差别。</p>
<div class="cnblogs_code">
<pre>beforeEach(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    TestBed.configureTestingModule({
      imports: ,
      declarations:
    });
});</span></pre>
</div>
<p>2 TestBed创建组件:TestBed.createComponent</p>
<p>创建组件,返回一个fixture。fixture 包括组件实例、变更监测以及DOM相关的属性,它是用来写单元测试的核心。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">@Component({
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   template: `&lt;trade-view ="id" (close)="_close()"&gt;&lt;/trade-view&gt;`
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">class TestComponent {
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   id: number = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">    _close() { }
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> beforeEach(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">    TestBed.configureTestingModule({
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">      imports: ,
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">      declarations:
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">    });
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   fixture =<span style="color: rgba(0, 0, 0, 1)"> TestBed.createComponent(TestComponent);
</span><span style="color: rgba(0, 128, 128, 1)">15</span>   component =<span style="color: rgba(0, 0, 0, 1)"> fixture.componentInstance; //组件实例
</span><span style="color: rgba(0, 128, 128, 1)">16</span>   el =<span style="color: rgba(0, 0, 0, 1)"> fixture.nativeElement; //组件原生元素</span><span style="color: rgba(0, 128, 128, 1)">17</span> });</pre>
</div>
<p>&nbsp;3 异步beforeach(具体可参考angular官方文档 测试-调用compileComponents())</p>
<p>如果一个组件使用了templateUrl和styleUrls获取模板或者模板样式,这是一个异步的过程,那么需要使用异步beforeach创建组件,否则会报错无法编译组件。</p>
<p>如下是没有使用异步beforeach创建组件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> beforeEach(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)">TestBed.configureTestingModule({
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 0, 1)">    declarations: [ BannerComponent ],
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 0, 1)">});
</span><span style="color: rgba(0, 128, 128, 1)">5</span>   fixture =<span style="color: rgba(0, 0, 0, 1)"> TestBed.createComponent(BannerComponent);
</span><span style="color: rgba(0, 128, 128, 1)">6</span> });</pre>
</div>
<p>如果这个组件没有使用templateUrl或styleUrls,那么不会有任何问题,因为createComponet就会执行组件的编译,然后再创建组件。但如果使用了templateUrl或styleUrls,则获取url地址文件的过程是异步的,在createComponent时如果没有返回地址,那么执行编译就会报错。这时,用异步的beforeach来解决这个问题。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> beforeEach(async(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> { //使用angular提供的辅助异步函数
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">TestBed.configureTestingModule({
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">    declarations: [ BannerComponent ],
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">.compileComponents()
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>   .then(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>   fixture =<span style="color: rgba(0, 0, 0, 1)"> TestBed.createComponent(BannerComponent);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>   component =<span style="color: rgba(0, 0, 0, 1)"> fixture.componentInstance;
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>   h1 = fixture.nativeElement.querySelector('h1'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">});
</span><span style="color: rgba(0, 128, 128, 1)">11</span> }));</pre>
</div>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/hahlzj/p/11294630.html
頁: [1]
查看完整版本: angular单元测试学习(jasmine)