読者です 読者をやめる 読者になる 読者になる

spring of life

技術、ときどき日常のブログ(予定)

Robotium でダイアログの操作

AndroidのテストでUIの操作する時にRobotium使ってて、今回ダイアログの操作をする必要が出てきたのでちょっと調べてみた。
まぁ大した話じゃないんだけどw

solo.clickOnView(solo.getView(R.id.select_category));  // ダイアログを表示するボタンを押下(ビューのIDで指定)
solo.waitForDialogToOpen();  // ダイアログが表示されるまで待つ 
solo.clickOnText("test");  // "test"を選択(表示されている文字列で指定)
solo.clickOnButton("OK");  // "OK"ボタンを押してダイアログを閉じる(表示されている文字列で指定)
  • soloはRobotiumで定義されているSoloクラスのインスタンス
  • ダイアログにはセレクトボックスが表示されている

Android + Mockito でテスト

また家計簿のアプリの話で、WebAPIを実行する時に使うHTTPクライアントのテストをする時にモックを使ってみた

インストール

下記のページを参考にjarを3つlibsに追加

y-anz-m.blogspot.jp

ただ、記事がちょっと古くて?dexmakerとかのダウンロードページへのリンク先が404なので、こちらからダウンロード

あとは、ダウンロードしたjarをlibsの下に入れてビルドパスの設定したら完了!

使い方

↓みたいな感じでモックを作成するメソッドを作ってみた

private void setupMock(HTTPClient httpClient, int statusCode, final String responseBody) {
  try {
    when(con.getResponseCode()).thenReturn(statusCode);
    when(con.getInputStream()).thenReturn(new InputStream() {
      private int position = 0;
      @Override
      public int read() throws IOException {
        return position < responseBody.length() ? responseBody.charAt(position++) : -1;
      }

      @Override
      public void close() throws IOException {}
    });

    Class<? extends HTTPClient> c = httpClient.getClass();
    Field f = c.getDeclaredField("con");
    f.setAccessible(true);
    f.set(httpClient, con);
  } catch (NoSuchFieldException e) {
    e.printStackTrace();
  } catch (IllegalArgumentException e) {
    e.printStackTrace();
  } catch (IllegalAccessException e) {
    e.printStackTrace();
  } catch (IOException e) {
    e.printStackTrace();
  }
}

conHttpURLConnectionクラスのインスタンスで、HTTPClientがフィールドとして持ってるので、それをモックに差し替える感じ

で、connect()を実行した時に接続して欲しくないので、

@Before
public void setUp() throws Exception {
  super.setUp();
  System.setProperty("dexmaker.dexcache", getContext().getCacheDir().getPath());
  con = mock(HttpURLConnection.class);
  doNothing().when(con).connect();
}

みたいに、doNothing()を使って文字通り何もしないように事前に設定しておく

あと、android で mockito を使う場合はプロパティ設定が必要らしい(自分の場合は下記記事のパターン2が必要だった)

qiita.com

複数選択ダイアログ作成

Android 初心者すぎてちょっと機能足すのにも結構時間かかる。。。

  • 家計簿のアプリで、費目(食費、交通費とか)を今まではキーボードで入力してたけど、選択できるようにした
  • 費目の入力欄のところにボタンを付けて、それを押すとダイアログが出てきて、表示される費目のリストを複数選択する感じ
  • 費目のリストは収支情報が登録されているサーバーのRailsアプリに実装されているWeb APIを使って取得できるようになっている

ビューの作成

カスタムビュー

今回、カスタムビューと呼ばれるものを作ってみたんだが、結構詰まった。。。

qiita.com

ここらへんを参考にしたかな〜

まだinflateとかの使い方がよく分からなくて、
View.inflate(context, R.layout.input_form, this);でビューが生成されるのがようやく分かった。。。

View layout = View.inflate(context, R.layout.registration_view, this);

inputViews = new InputView[INPUT_VIEW_SIZE];
inputViews[INPUT_VIEW_DATE] = (InputView) layout.findViewById(R.id.date);
inputViews[INPUT_VIEW_CONTENT] = (InputView) layout.findViewById(R.id.content);
inputViews[INPUT_VIEW_CATEGORY] = (InputView) layout.findViewById(R.id.category);
inputViews[INPUT_VIEW_PRICE] = (InputView) layout.findViewById(R.id.price);

1度inflateでビューを生成して、その後はfindViewByIdでビュー取得かな

キーボード設定

金額とか数字を入力するのが分かってる場合は、android:inputType="number"とか使うとデフォルトで数値入力のキーボードになってる

他にもいろいろ設定できるようで、下記にいろいろ書いてある

kuwalab.hatenablog.jp

文字の左右中央寄せ

android:gravityで設定できるっぽい

seesaawiki.jp

ちなみに、右寄せにしようとandroid:gravity="right"にしようとしたら警告が出て、android:gravity="end"にしろって言われた。。。

ダイアログの作成

参考にしたのは↓かな。というかコピペして、ちょっと修正するだけでいけたw

androidkaihatsu.seesaa.net

このサイトのサンプルは選択肢が固定値だったので、それをWeb APIを使って動的に作るようにした

その他メモ

res/values-ja/strings.xmlに入ってる文字列情報はgetResourcesメソッドとかを使うと取れるっぽい

getResources().getString(R.string.date);

参考サイト:
android.keicode.com



これでとりあえず参考になったサイトは全部貼り付けたかな。。。w

忘れないように貼り付けていかないと次思い出そうとした時に面倒だからな〜ブクマでもいいんだけどね

シーケンス図・クラス図の書き方 etc

自分で仕様書書くときに sphinx で plantuml 使ってて、主にシーケンス図・クラス図を書いてるので、参考にしたページをペタペタ貼っておきます(と言っても同じサイトですが。。。)

  • シーケンス図

yohshiy.blog.fc2.com

  • クラス図

yohshiy.blog.fc2.com

というか多分、検索したらトップに出てくるから載せる必要もないかもw

まぁ自分が作ってるアプリだと、このサイトの載ってるので十分UML作れるかな


あと、emacs で書いてるので専用のパッケージを入れてみた。手順としては

1. .emacs.el にパッケージの追加

(add-to-list 'package-archives '("melpa-milkbox" . "http://melpa.milkbox.net/packages/") t)

2. パッケージインストール

# emacs コマンド実行後
M-x package-install [RET] plantuml-mode [RET]

3. plantuml-mode 自動適用設定

(require 'plantuml-mode)
(add-to-list 'auto-mode-alist '("\\.uml$" . plantuml-mode))
(setq plantuml-jar-path "/path/to/plantuml.jar")

M-x plantuml-previewで作成中のUML図が emacs 上で見れるのが結構便利だった!

テストのスキップ判定

RSpecで、itのオプションに:ifやら:unlessやらあるらしくて、それを使うことでスキップの判定ができるらしい。知らんかった。。。

ちなみにRSpecのバージョンは3.4.1でした

% bundle exec rspec -v
3.4.1

書き方は普通に条件判定する文を値に持ってくる感じでOK。ブロックになってるのかな〜詳しく調べてないんだけど

it 'hoge test', :if => 1 == 1 do
  expect(hoge).to eq fuga
end

詳しいことは↓のあたりを参考に

www.relishapp.com

jbuilder の使い方2

前に こういう記事を書いたんだけど、結構見られてるんだよね笑

leonis.hatenablog.com

で、1つ前の記事で多対多の関連を作ったというのを書いて、同時にレスポンスの json の形式も↓のように変えてみた

# 変更前
{
  "payment_type": "income",
  "date": "2017-04-16",
  "content": "hogehoge",
  "category": "fuga",
  "price": 100
}
# 変更後
{
  "payment_type": "income",
  "date": "2017-04-16",
  "content": "hogehoge",
  "categories": [
    {"id: 1, "name": "fuga"}
  ],
  "price": 100
}

もともとカテゴリは複数付くのを想定してたんだが、適当にカンマ区切りの文字列にしてた。。。

で、まぁ今回ちょっとカテゴリをリソース化してみようと思って、ついでにレスポンスも真面目に考えることにした(。-_-。)

ここからが本題↓

途中に関連するモデルの属性を入れる時

↑でいう変更後の json を作ってみる

json.(@payment, :payment_type, :date, :content)
json.(@payment.categories, :id, :name)
json.(@payment, :price)
# payment_type, date, content, price は@payment の属性
# id, name は@payment に関連しているカテゴリ情報の属性

単純に上から順番に属性を書いていけばいいだけなんですね。。。わかりやすい。。。

多対多の関係のモデル作成

今回はhas_and_belongs_to_manyを使う方法で実装してみた

  • 例として、というか自分が家計簿のアプリで実装したのは、収支情報(payment)とカテゴリ(category)の関連の作成
  • まずはスキーマの作成
    • 中間テーブルのファイル名はアルファベット順という規則(categories → payments )らしい
bundle exec rails g model payment
bundle exec rails g model category
bundle exec rails g migration create_categories_payments
  • payments と categories は好きに属性を追加するとして、中間テーブルの設定を以下のようにする
    • インデックスの設定とかはご自由にどうぞ、みたいな感じで
class CreateCategoriesPayments < ActiveRecord::Migration
  def change
    create_table :categories_payments, :id => false do |t|
      t.references :category, :index => true, :null => false
      t.references :payment, :index => true, :null => false
    end

    add_index :categories_payments, [:category_id, :payment_id], :unique => true
  end
end
  • モデルに関連を追加する
# app/models/payment.rb
class Payment < ActiveRecord::Base
  has_and_belongs_to_many :categories
  ...
end

# app/models/category.rb
class Category < ActiveRecord::Base
  has_and_belongs_to_many :payments
  ...
end

これでincludesとかjoinsとかが使えるようになる
例えば、カテゴリで検索をかける場合、

# app/models/payment.rb
class Payment < ActiveRecord::Base
  has_and_belongs_to_many :categories
  ...
  scope :category, ->(category) { joins(:categories).where('categories.name = ?', category) }
  ...
end

みたいな感じで書いといて、コントローラー側とかで

def index
  ...
  Payment.category('食費')
  ...
end

と書けば、name属性が食費のカテゴリが付いてる収支情報が取れる


問題はここからなんだよなぁ。。。
ビューにはどう書くとキレイなんだろ?
カテゴリとか今入力してるとこを選択するようにしたいし、リストの先頭を空欄にして、そこに新しいカテゴリを入力して登録すればカテゴリが新規作成されるようにしたい