在TypeScript + Angular1项目中编写单元测试

在准备给基于Angular1的产品进行测试时,需要进行环境设置和实际测试代码的编写等工作。我将把这些内容整理在一起。

前提条件

    • TypeScript(v1.8, 含テストコード)

 

    • AngularJS(v1.4)

 

    karma+mocha+power-assert

代码不是采用现代的require依赖解析并进行bundle的方式,而是使用TypeScript的命名空间来进行范围划分,最后将其合并为一个单一文件并输出为tsc –outFile dist/bundle.js的形式。

在以下链接的GitHub存储库中,重现了环境:https://github.com/sisisin-sandbox/ngts/tree/master/namespace-style

使最低要求karma得以操作

在不同的选项中尝试过许多,但最终我决定参考这篇文章。

    • プロダクトコードはconcat済のものを参照(karma.conf.jsのfilesにはdist/bundle.jsを読ませる)

 

    テストコードはkarma-browserifyを利用し、browserify + tsify + espowerifyでts -> espoweredなjsにして実行

在参考产品代码的同时编写测试代码,并在断言错误时能够详细查看power-assert的错误提示,我们得到了这样的结果。

用karma运行Directive的测试。

当以Directive使用templateUrl引用html时,可能会出现以下错误,并导致测试失败。

    Error: Unexpected request: GET /views/appHelloDirective.html
    No more request expected
        at $httpBackend (/var/folders/0q/d6gvmfsn7gv849kw__r2py_00000gp/T/node_modules/angular-mocks/angular-mocks.js:1418:0 <- /var/folders/0q/d6gvmfsn7gv849kw__r2py_00000gp/T/cd8d66ce58eb2b84e246e72fab23a78f.browserify:1727:9)
        at sendReq (node_modules/angular/angular.js:11776:9)
        at serverRequest (node_modules/angular/angular.js:11571:16)
        at processQueue (node_modules/angular/angular.js:16383:28)
        at node_modules/angular/angular.js:16399:27
        at Scope.$eval (node_modules/angular/angular.js:17682:28)
        at Scope.$digest (node_modules/angular/angular.js:17495:31)
        at Context.<anonymous> (/var/folders/0q/d6gvmfsn7gv849kw__r2py_00000gp/T/test/directive-spec.ts:25:10 <- /var/folders/0q/d6gvmfsn7gv849kw__r2py_00000gp/T/cd8d66ce58eb2b84e246e72fab23a78f.browserify:17408:15)

为了避免这个问题,我们可以使用karma-ng-html2js-preprocessor这个包。
这个包可以将以Angular模板编写的html文件转换为js文件,并且可以适应karma的执行。
另外,还提供了解决templateUrl文件路径的选项,即使运行时的路径与当前目录不同,也可以灵活处理。

写测试时的方针。

总体方针

    • Angularに依存している部分はanuglar-mocksでモックしつつテストする

Directive,$scope,$httpなど

DI対象が多い場合やネストしてる場合もangular-mocksを利用してやる
それ以外はなるべくangular-mocksを利用しないでjs(ts)オンリーでテストを書く

薄いControllerや$httpを利用しないService,Factoryなど

テスト用のデータは関数で取得するようにする

例:const data1 = () => [1, 2, 3];

生のオブジェクトや配列を$scopeなどに渡すとAngularの方でプロパティ生やされたりするので($$hashKeyなど)

指令

    • 極力attributeから渡された値がControllerにbindされていることを確認するのみに留める

link関数などで盛大にロジックが書かれてしまっている場合

一旦ロジックに対してもテストを書く
しかる後にロジックをテストとともにControllerに分離してbindToControllerに書き直し、link関数を撲滅する

基本上,我认为如果按照@armorik83先生的现代实践和@laco0416先生的AngularJS老化检查编写方法,你就能够确保可测试性。

课题(或者说尚未清晰可见的事物)

compileやlink関数内で動的に出力するtemplateを差し替えていたりする場合のテストをどうするか

控制器

$scopeなどに依存してない部分は普通にテスト書く

$scope.$watchなどに依存している場合

$watchに登録したコールバック関数の処理が単純なら振る舞いをそのままテストする
複雑な場合は、コールバック関数をプロパティなどにして、$watchの発火のテストとコールバック関数についてのテストを分割する(この辺参照)

ここでarrow function使っておかないとthisの扱いで爆死するので注意
そもそもそんな複雑なことやるなという話

テストを書いたら、$scope依存は消せそうか検討して極力消す。

$scopeのプロパティを利用していた場合

全てControllerのプロパティへ移植する

Directiveに紐づいていた場合はbindToControllerを利用

服务,工厂

$http, $resoucesに依存している場合

$httpBackendを利用してAPIレスポンスをモックしてテスト

それ以外は普通にテスト書くだけ(多分

过滤

只是一个普通函数,所以我认为没有太多需要做特别的事情。

最后

因此,在TypeScript + Angular1系环境中,我简单地总结了如何构建单元测试环境以及编写测试代码的方针。由于我只是在我目前涉及的项目中进行编写,所以可能不是十分全面,但希望能对您有所帮助。

广告
将在 10 秒后关闭
bannerAds