JavaScriptとTitaniumではじめる iPhone/Androidアプリプログラミング の執筆をされている森さんが昨年末のAdventCalendar【13日目】イベント機構&リトライ機構を組み込んだHTTPClient (Titanium Mobile)というエントリを書かれた際に、以下の様なことを書かれていました
- 通信結果を取得するコールバック関数をcreateHTTPClient時に書かないといけない
→ View のように addEventListener な感じで書きたい
2. 通信環境があまり安定しないスマートフォン向けだけどリトライがない
→ もちろん呼び出し元でやればいいんだけどさ
自分もQiitaのビューワーアプリ作っていて、HTTPClientのリトライ機能欲しいなぁと思っていたので、TDD/BDDなスタイルで機能拡張していく過程についてしばらくご紹介していこうと思ってます
解説の前に作業環境など
- Titanium Command-Line Interface (CLI version 3.0.23)とTitanium SDK version 3.0.0.GAにて確認してます。
- ひとまず iOSのみをターゲットにしてます。なお私の実機はまだ5.x系なのでTitanium Command-Line Interface使ってbuildする時には「titanium build -p iso -S 5.1 」として作業してます。(たぶん6.x系でも動作すると思いますが未確認です)
- CoffeeScriptでコード書いてますが、Coffeeから生成されるJavaScript含めて 全てソースコードはGitHubにあります
- TDD/BDDなライブラリとしてjasmine使って作業してきますが、環境構築などは以前書いたエントリを参考にしてください
- ディレクトリ構造は以下を想定しておりcoffee/test配下にテストコードを配置してます
├── LICENSE ├── README.md ├── Resources ├── build │ ├── xxxx ├── Resources │ ├── app.js │ ├── lib │ │ ├── jasmine-1.3.1.js │ │ ├── jasmine-titanium-console.js │ │ ├── jasmine-titanium.js │ │ ├── jasmine.async.min.js │ └── test │ ├── httpClient.js │ └── tests.js ├── coffee │ ├── app.coffee │ ├── httpClient.coffee │ └── test │ ├── httpClient.coffee │ └── tests.coffee ├── manifest └── tiapp.xml
app.coffeeとtest/tests.coffeeはそれぞれ以下のようになってます
app.coffee
testsEnabled = true if testsEnabled is true require('test/tests') else Ti.API.info "start apps"
test/tests.coffee
( () -> if testsEnabled Ti.include('lib/jasmine-1.3.1.js') Ti.include('lib/jasmine.async.min.js') require('lib/jasmine-titanium-console') require('test/httpClient') jasmine.getEnv().addReporter(new jasmine.TitaniumReporter()) jasmine.getEnv().execute() )
httpCLientクラスを作成
まずは、httpClientクラスを作成して、インスタンス化出来るかどうかを確認する簡単な所から初めます。jasmineのテストコードを以下のように書きます
test/httpClient.coffee
describe 'httpClient', -> beforeEach -> httpClient = require('httpClient') @client = new httpClient() it 'should be object', -> expect(typeof @client).toBe "object"
これで実行しますが、以下のようにまだ何も実装してないのでErrorになります
[ERROR] Jasmine: Suite TOTAL: 0 of 1 expectation passed. [INFO] Jasmine: F [ERROR] Jasmine: initialize [ERROR] Jasmine: - should be object ... Failed. [ERROR] Jasmine: => Expected 'undefined' to be 'object'. [ERROR] Jasmine: Suite TOTAL: 0 of 1 expectation passed. [ERROR] Jasmine: Runner TOTAL: 0 of 2 spec passed. [INFO] Jasmine: Runner Finished.
ひとまずhttpClientクラスを以下のように実装します
httpClient.coffee
class httpClient constructor: (args) -> module.exports = httpClient
テスト実行すると以下のようにテストはパスしました
[INFO] Jasmine: Runner Started. [INFO] Jasmine: . [INFO] Jasmine: Runner TOTAL: 1 of 1 spec passed.
httpCLientのタイムアウトの設定に関するテストケースを追加
httpClientクラスにひとまずhttpCLientのタイムアウトの設定に関するプロパティを設定します。jasmineのテストコードを以下のようにします
test/httpClient.coffee
describe 'httpClient', -> beforeEach -> httpClient = require('httpClient') @client = new httpClient() it 'should be object', -> expect(typeof @client).toBe "object" it 'has Timeout seconds', -> expect(@client.httpTimeout).toBe 5000
これでテスト実行しますが、httpClientのhttpTimeoutプロパティに関する実装をしてないので以下のようにテストは失敗しますね
[ERROR] Jasmine: httpClient [ERROR] Jasmine: - has Timeout seconds ... Failed. [ERROR] Jasmine: => Expected undefined to be 5000. [ERROR] Jasmine: Suite TOTAL: 1 of 2 expectation passed. [ERROR] Jasmine: Runner TOTAL: 1 of 2 spec passed.
httpClientクラスを以下のように修正します
httpClient.coffee
class httpClient constructor: (args) -> args = args or {} # HTTPClientのタイムアウト(ミリ秒) @httpTimeout = args.httpTimeout or 5000 module.exports = httpClient
この状態で再度テスト実行すると以下のようにテストにパスしてます
[INFO] Jasmine: Runner Started. [INFO] Jasmine: .. [INFO] Jasmine: Runner TOTAL: 2 of 2 specs passed. [INFO] Jasmine: Runner Finished.
今日はひとまずここまでにして、次回はHTTPClientとしてのメイン機能を取り込む所の実装についてご紹介していこうと思ってます