初めましてGTです!
e2eとは?node?Protractor?Angular?Cucumber....キュウリ??
IT系専門学校を卒業したものの、e2eテストやjsなどさっぱりわからない。
卒業後5か月はプログラムとほぼ縁のない業務をずっとして、プログラミングを忘れかけていました。
そんな社会人1年生がここ3か月間e2eテストの業務に携わってみました。
そこで、自分の体験談や苦労した点について書いていこうかと思います。
とりあえず環境を構築
e2eテストってなに?何をどうすればいいの?
目的を果たすための手段やツールの名前が分からないけど、とりあえず手を動かして環境を構築してみました。
今回業務で使用した主なツール(分かる範囲で)
- Protractor5.1.2←Angularのテストフレームワーク、便利
- cucumber1.3.2←テストシナリオ作るフレームワーク
- node8.5.0
- VSCode1.18.1
- Github
主なツールをインストールしたものの、次に何したらいいか分からない。
とりあえずプロジェクト内の他の人が書いたコードを見ながらコード書いてみようか。
コーディング
の前に、e2eテストについてはネットで調べて、何の目的で行い、どうすればそういうプログラムが書けるのかを勉強しました。
以下、初心者である自分なりの解釈
どうやらテストシナリオというものがあって、このシナリオに沿った操作を行えばいいみたい。
e2eの目的:自動でテストを楽にするため。ドキュメント(テスト結果)残すため。
作り方:po、step、featureという3つのファイルを作る
.po ・・・DOMを取得する操作だけを書くファイル
.step・・・poを使ってシナリオに沿った操作を書くファイル
.feature・・・stepファイルをシナリオ通りに並べるファイル
po→step→featureの順で作ると分かりやすい。
勉強初めの頃にこんな例があれば分かりやすかったのにという例を書いてみる。
例:
下記画像のようなWebページがあるとする。
以下のテストシナリオを作成せよ。
1.ログインボタンを押す
2.タイトルが「SysDev」になっているか確認する
3.ログアウトボタンを押す
sample.po.ts import { by, element } from 'protractor'; //使うモジュールをインポート。他にも$とか色々ある export class LoginOut{ //stepで使うためにクラスをエクスポート getLoginButton() { return elment(by.css('loginbutton')); //ログインボタン要素取得 } getLogoutButton() { rerurn element(by.css('logoutbutton')); //ログアウトボタン要素取得 } getTitleText() { return element(by.css('titletext'); //タイトル要素取得 } }
sample.step.ts import { browser } from 'protractor'; import * as chai from 'chai'; //expect(評価関数)を使うためにchai(フレームワーク)をインポート import { LoginOut } from '../po/sample.po'; //使うpoファイルをインポート export default function(){ //stepを作る魔法 const LoginOut = new LoginOut(); //poのclassを使う魔法 this.Given(/^Login Click$/, async function() { // /^$/の間にstep名書く。あとは魔法。このthisから始まるstep一つ一つが関数のようなものになる。 await browser.waitForAngular(); //Angularのレンダリング終了を待つ。魔法的な。 await LoginOut.getLoginButton().click(); //poで要素取得して、取得した要素に対してクリック操作をする。 }); this.Given(/^Logout Click$/, async function() { await browser.waitForAngular(); await LoginOut.getLogoutButton().click(); }); this.Then(/^Title Check$/, async function() { await browser.waitForAngular(); chai.expect(await LoginOut.getTitleText().getText()).to.equal('SysDev'); //titleのtextを取得して文字列SysDevと比較評価。違ってたらプログラム止まる。 }); }
sample.feature.ts @active //activeなら動くdisabledなら止まる。 Feature: Login And Logout //ここらへんは↓ User Can Login And Logout //人が識別するための↓ Scenario: User Can Login And Logout //ただの文字列的な。ちなみにconsoleには表示される。 Given Login Click //stepで書いた英語とstep名を書く Then Title Check //シナリオに沿って操作(step名)を並べる Given Logout Click //GievnとかThenとかは識別用?動きにはあまり関係ないぽいぞ
このような感じでe2eテストのシナリオを作成していく。(分かり辛かったらすみません)
一応、上記の3ファイルで例題のシナリオ通りには動く(はず)。
感想
いかにpoファイルを充実させるかが大切だと思った。
poで全てのDOMを取得して、stepを作成する。(←step作成が難しい)
featureは順番に並べるだけ、stepでややこしい名前を命名していなければ簡単。
だと思いました。
苦労した点と解決策
- 用語とかやっていることが意味分からない!
- 勉強したり人に聞いたり既にあるコードを見たりで、ある程度は解決。
未だによく理解してない部分はそういう魔法なんだと思ってる。
- 勉強したり人に聞いたり既にあるコードを見たりで、ある程度は解決。
欲しいDOMが取得できない!
- 他の要素が重なっていてnot visibleとなって取得できない。
ウィンドウサイズが原因だったため、
browser.driver.manage().window().maximize();
でウィンドウを最大化して解決。 マウスオーバー要素もnot visibleとなっていたので、
browser.action().mouseMove(element(by.css('マウスオーバー要素'))).perform();
でマウスを重ねて要素表示させて解決。input要素のvalueが欲しいのに何をやってもundefined。
見えてる要素が取れんわけないやん、getAttribute('value')
で解決。
使ったことない関数を使うことの大切さを学びました。。他にも、idが振られてない同名要素が複数ある場合、for文で回してtextなどをifで拾って解決。
- 他の要素が重なっていてnot visibleとなって取得できない。
シナリオの要求が難しくなった!
DBのテーブルをDROPするシナリオがあり、exec関数を使ってshellを走らせた。
zipファイルをダウンロード→解凍→Checkするシナリオ、同じくexec関数で解決。
execって便利デスネ!!
linuxのコマンドなら一発なのにな~って思う場面が意外と多く大活躍!
システムのバージョンアップ毎にclass名や機能が変わったりした!
作成したシナリオが増えているほど修正点が増えるため、単純に修正作業に時間がかかっちゃう。
システム内にidはなくclass名のみ、しかもバージョンアップ頻度高かった。step名にパラメータを渡せるため、複数シナリオで使いませるstepを作成して修正箇所を減らしたり、根気でちまちま修正して解決。
修正といっても単純作業なので結構慣れる。
e2eテストやってみての所感
e2eテストが何のために行われるのかを考えたりしました。
普通、テストはバグを発見するために行います。
e2eテストはユニットテストと違い、システム全体をテストするものです。
ということは全体のバグを発見するのでしょうか?
ある意味合ってるけど、ある意味違うような気がします。
作成したシナリオを通じて思ったのですが、重要な処理部分に関するシナリオが多かったので、
e2eテストはシステムの中でも特にクリティカルな部分をテストするためにあるのかなぁ、なんて考えたり。
間違ってたらすみません(笑)
今後取り組みたいこと
- stepファイルの簡略化
- 用語の理解
- ファイル操作などを伴う複雑なシナリオ
- どんな場面にe2eテストが使われるのか考える
社会人になって初めて取り組んだプログラミング開発の仕事が今回のe2eテストコード作成でした。
テストを作って実行すると、Webブラウザが立ち上がって自動的に動き出すので、普通に楽しかったです。
作って結果がすぐ返ってくるというスピーディ感が個人的にはとても好きでした。
今回のブログでは書ききれなかったネタがまだあるので、またの機会に投稿したいと思います。