TitaniumMobile勉強記

Web系エンジニア向けのキャリアアドバイザーやってましたが現在はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連(Node.js、Titanium)あたり

Ti.Network.HTTPClientを少し機能拡張しながらjasmineの使い方について学ぶ-part1

JavaScriptとTitaniumではじめる iPhone/Androidアプリプログラミング の執筆をされている森さんが昨年末のAdventCalendar【13日目】イベント機構&リトライ機構を組み込んだHTTPClient (Titanium Mobile)というエントリを書かれた際に、以下の様なことを書かれていました

  1. 通信結果を取得するコールバック関数を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としてのメイン機能を取り込む所の実装についてご紹介していこうと思ってます