【SAPUI5】チュートリアルを見ながらTest Driven Developmentを体験する (5) 検索機能 

##OPA5で検索機能のテスト
リストの上にSearch Fieldを追加し、入力した内容に一致する結果が表示されることをテストします。今回のポイントはOPA5で入力操作をするところです。

参考にするチュートリアル
[Step 11: Testing User Input](https://sapui5.hana.ondemand.com/#/topic/92959b10ecf14582b65eaadb40571156)
[Step 12: Adding a Search](https://sapui5.hana.ondemand.com/#/topic/0c270b45dd904429ba634656e3a37a73)

「チュートリアルを見ながらTest Driven Developmentを体験する」シリーズの目次は[こちら](https://qiita.com/tami/items/5776597e19337f57fa34)

##User Journey

- リストの中から特定の単語("Bear")を検索する
- リストに1件だけ表示される（絞り込まれた結果）

##テスト用の構成
今回はWorklistJourney.jsとWorklist.jsにコードを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/69a71868-2004-5bfa-0d77-cf33b5e8d652.png)

###test/integration/WorklistJourney.js
以下のテストを追加します。

```javascript
	opaTest("Should be able to search for items", function (Given, When, Then){
		// Actions: "Bear"を検索
		When.onTheWorklistPage.iSearchFor("Bear");
		
		// Assertions: リストに1行だけ表示される
		Then.onTheWorklistPage.theTableHasOneItem();
		
		// Cleanup
		Then.iTeardownMyApp();		
	});
```

アプリを閉じる処理である`Then.iTeardownMyApp();`はもともと一つ前のテストの最後にありましたが、追加したテストの最後へ移動します。

###test/integration/pages/Worklist.js

検索欄へ入力するため、EnterTextをdependencyに追加します。

```javascript
sap.ui.define([
		'sap/ui/test/Opa5',
		'sap/ui/test/matchers/AggregationLengthEquals',
		'sap/ui/test/matchers/I18NText',
		'sap/ui/test/matchers/BindingPath',
		'sap/ui/test/actions/Press',
		'sap/ui/test/actions/EnterText' ←追加
	],
	function (Opa5,
			  AggregationLengthEquals,
			  I18NText,
			  BindingPath,
			  Press,
			  EnterText) ←追加{ 
```

アクションを追加します。

```javascript
					iSearchFor: function(sSearchString) {
						return this.waitFor({
							id: "searchField",
							viewName: sViewName,
							actions: new EnterText({
								text: sSearchString
							}),
							errorMessage: "SearchField was not found."
						});
					}
```

アサーションを追加します。

```javascript
					theTableHasOneItem: function () {
						return this.waitFor({
							id: sTableId,
							viewName: sViewName,
							matchers: new AggregationLengthEquals({
								name: "items",
								length: 1
							}),
							success: function() {
								Opa5.assert.ok(true, "The table contains one corresponding entry");
							},
							errorMessage: "The table does not contain one item"
						});
					}
```
###実行してみる
実行すると、SearchFieldが見つからなかったというエラーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/c99d73e8-6111-3f65-83d2-49fdf7f1802b.png)

##検索機能を実装する

###webapp/view/Worklist.view.xml
ヘッダに検索窓を追加します。

```xml
				<headerToolbar>
					<Toolbar>
						<Label id="tableHeader" text="{worklistView>/worklistTableTitle}"/>
						<ToolbarSpacer /> ←追加
						<SearchField id="searchField" width="auto" search=".onFilterPosts" /> ←追加
					</Toolbar>
				</headerToolbar>
```

`<ToolbarSpacer />`は、検索窓を右寄せにするために入れているスペーサーです。
実行すると、以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/d325dad9-9027-0d7a-2021-ca13500e7eef.png)

###webapp/controller/Worklist.controller.js
検索ボタンを押したときに呼ばれる機能を実行します。
まずはdependencyとして、FilterおよびFilterOperatorを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/11c3f454-2558-a61d-aee4-707a98924afe.png)

検索用のファンクションは以下のように実装します。ここでは、Titleという項目が検索窓に入力した文字列を含むものを抽出します。

```javascript
		onFilterPosts: function (oEvent) {
			//buld filter array
			var aFilter = [];
			var sQuery = oEvent.getParameter("query");
			if(sQuery) {
				aFilter.push(new Filter("Title", FilterOperator.Contains, sQuery));
			}
			
			// filter binding
			var oTable = this.byId("table");
			var oBinding = oTable.getBinding("items");
			oBinding.filter(aFilter);
		},
```

###動作確認
フィルタに入力すると、Nameの項目で出力レコードが絞られました。（Titleという項目にバインドされているが、表示上はName）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/31c7a6ac-150a-3d0b-e9b1-7b075088b560.png)

##テストを実行
検索機能に関するテストが正常終了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/0b5cfabd-5f25-7731-b592-8e2d4bf1fe34.png)

##感想
「チュートリアルを見ながらTest Driven Developmentを体験する」と題して、QUnitテスト、OPA5テスト実行の流れについて書いてきました。
QUnitに関しては、テスト書き方が比較的シンプルで、機能を実装する前にテストを書くということの有効性が実感できました。
一方OPA5は、テストがちゃんと動くところまで持っていくところで苦労しそうだと感じました。そこに労力を割くのであれば、人がテストしたほうが早いのではと思ったり。
「こういう操作の場合はこういう書き方をする」ということがある程度定型化されて、あまり考えなくてもテストが書ける状態であればOPA5も有効なのかもしれません。

##関連記事
[チュートリアルを見ながらTest Driven Developmentを体験する (4) ナビゲーション](https://qiita.com/tami/items/c9d5e2d8cc34c07b5a74)