Android Studio + Robolectricで自動テスト
Androidでの自動テストはRobolectricというフレームワークを使うのが良いと聞いたので導入してみました。
導入方法と僕が詰まった箇所の解決法を書いておきます。
導入方法は
【Android】Android Studio + Gradle + Robolectric!でテストをしよう | Yohei Blog
こちらを参考にさせて頂きました。
公式サイトは Robolectricです。
導入方法
build.gralde
project直下のbuild.gradleにclasspath 'org.robolectric~
を追記します。
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.12.+' classpath 'org.robolectric:robolectric-gradle-plugin:0.12.+' } }
app/build.gradle
apply plugin: 'android' //プラグイン追加 apply plugin: 'robolectric' android{ //〜中略〜// } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) //ライブラリを追加 androidTestCompile('junit:junit:4.+') androidTestCompile('org.robolectric:robolectric:2.3+') androidTestCompile('com.squareup:fest-android:1.0+') } //robolectricの設定を追記 robolectric { include '**/*Test.class' exclude '**/espresso/**/*.class' maxHeapSize = "2048m" // エラーの原因かもしれない }
テスト用クラスを作成
クラスを作成するディレクトリはapp/src/test/java
になります。
packageはメインのプロジェクトと同じにしてください。
@RunWith(RobolectricTestRunner.class) @Config(emulateSdk = 18) //後述 public class SampleTest { @Before public void setup() { // setup } @After public void teardown() { // teardown } @Test public void sampleTest() { Assert.assertTrue("assert",true); } }
テスト実行
~/.gradlew clean check
BUILD SUCCESSFUL
となれば成功です。
1 test completed, 1 failed :app:testDebug FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:testDebug'. > There were failing tests. See the report at: file://~/app/build/test-report/debug/index.html * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. BUILD FAILED Total time: 16.035 secs
上記のように出力された場合はテストが失敗しています。
テストレポートは{project}/app/build/test-report/debug/index.html
で確認できます。
上手くいかない場合
パッケージorg.junitは存在しません
まず最初に、ビルド時にorg.junitは存在しません
というエラーが出ました。
app/src/test/java
ディレクトリは、android studio上でNew→Folder→Java Folder
という手順で作成しましたが、その際に
app/build.gradle
にこのように追記されていました。
SourceSets { androidTest.setRoot('src/test') main { java.srcDirs = ['src/main/java', 'src/test/java'] } }
フォルダ作成時にどのような手順をとれば良いかはわかりませんが、上記をこのように変更することでビルドが通ります。
SourceSets {
androidTest.setRoot('src/test')
}
too small initial heap
次に、too small initial heap
というエラーが出ました。
app/build.gradle
のプラグイン設定でmaxHeapSize
という項目を削除したら解決しましたが、この記事を書くために再び追記してみたらエラーは出ませんでした...。謎です。
java.lang.UnsupportedOperationException
java.lang.UnsupportedOperationException
というエラーが出た場合はsdkがサポートされていないということなので、アノテーションで@Config(emulatedSdk = 18)
と記述してやれば解決します。
長くなってしまいましたが導入にかなり苦戦してしまったので、同じようなエラーで悩んでいる方の一助となれば幸いです。
シェルスクリプト for文で引数全てに対し繰り返し処理を実行する
シェルスクリプトでfor文は基本的に
for x in $var1 $var2 $var3 do echo $x done
みたいな感じに変数や値を複数指定して使用しますが、
#for_echo.sh for x in "$@" do echo $x done
上記のように記述すると指定した引数全てに対し処理が実行されます。
in
以降は省略可能で
#for_echo.sh for x do echo $x done
この様に記述しても良いです。
$./for_echo.sh foo bar baz foo bar baz
基本的にin
以降は省略しないほうが良いようですが、省略できること自体知らなかったのでメモ。
Android SurfaceView でカウントダウンタイマー実装
最近Androidでゲームアプリを作成してて、カウントダウンタイマーを実装する時にちょっと詰まったのでメモ。
/** * 制限時間を計算 */ public class CalcTime { private final int GAME_TIME = 30; private long mNowTime; private long mStartTime; public CalcTime() { this.mNowTime = GAME_TIME; } // 現在の時間を返す public long getNowTime(){ return mNowTime; } // カウントダウン開始 public void startCountDown(){ mStartTime = System.currentTimeMillis(); } // 現在の時間を計算 // カウント終了でtrueを返す public boolean calc(){ long current = System.currentTimeMillis(); long time_gone = (current - mStartTime) / 1000; if(time_gone >= 30){ mNowTime = 0; }else { mNowTime = GAME_TIME - time_gone; } if(mNowTime == 0) { return true; } return false; } }
startCountDown()
で開始時間をセットして毎フレームcalc()
で計算、getNowTime()
で値を取得して表示すればOK。
↓表示例(SurfaceViewを継承したクラスで実装)
private CalcTime mCalcTime = new CalcTime(); private Boolean mClicked = false; @Override public void run() { while (thread != null){ if(mClicked){ mCalcTime.calc(); } this.onDraw(getHolder()); } } private void onDraw(SurfaceHolder holder){ Canvas c = holder.lockCanvas(); if(c == null){ return; } // 1の位 int ones_time = (int)mCalcTime.getNowTime() % 10; // 10の位 int tens_time = (int)mCalcTime.getNowTime() / 10; c.drawText(tens_time,0,0,paint); c.drawText(ones_time,0,FONT_SIZE,paint); holder.unlockCanvasAndPost(c); } @Override public boolean onTouchEvent(MotionEvent event) { if(event.getAction() == ACTION_DOWN){ mClicked = true; mCalcTime.startCountDown(); } return super.onTouchEvent(event); }
「rails server」実行時に「NoMethodError」がでた場合の対処法
第1章で
$ rails server自分の環境で上記を実行すると下記のようなエラーが発生した。
=> Booting WEBrick
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
/home/***/.rbenv/versions/2.0.0-p451/lib/ruby/gems/2.0.0/gems/railties-4.0.5/lib/rails/railtie/configurable.rb:30:in `method_missing': undefined method `application' for #<FirstApp::Application:0x0000060132cd30> (NoMethodError)対処法としては
$ vim ~/rails_project/firlst_app/config/environments/development.rb上記のような変更を加えればOK。
# ~/rails_project/firlst_app/config/environments/development.rb
# src
1 Rails.application.configure do
# dest
1 FirstApp::Application.configure do
こんな感じのエラーがでるのでDEPRECATION WARNING: You didn't set config.secret_key_base. Read the upgrade documentation to learn more about this new config option. (called from service at /home/YAMAMOTO_HI/.rbenv/versions/2.0.0-p451/lib/ruby/2.0.0/webrick/httpserver.rb:138)[2014-07-02 15:33:05] ERROR RuntimeError: You must set config.secret_key_base in your app's config.
$ rake secretして、出てきた文字列をコピー
$ vim ~/rails_projects/first_app/config/initializers/secret_token.rb以上
# ~/rails_projects/first_app/config/initializers/secret_token.rb
FirstApp::Application.config.secret_key_base = '***' ←コピーした文字列に置き換える
LinuxでICカードリーダが認識されないときの対処法
Epgrecの録画自体は成功しているのだが画面に何も映らない。
特に設定など弄っていないので原因がわからなかったがふとカードリーダを見たらランプが点滅していない。(点灯状態だと認識されていない)
カードもカードリーダも他のPCやTVに繋いだところ問題ないようだが、録画サーバに繋いだ時は
SCardEstablishContext: Service not availableだったので色々調べてみると、まずHALデーモンが起動しておらず、起動させようとしたら起動しなかった。
何故かmessagebusが起動していなかった模様。
[root@****]# service messagebus startシステムロガーを起動中: [ OK ][root@****]# service haldaemon startHAL デーモンを起動中: [ OK ][root@****]# service pcscd restartPC/SC スマートカードデーモン (pcscd) を停止中: [失敗]PC/SC スマートカードデーモン (pcscd) を起動中: [ OK ]
これで直った。
ポートフォワーディングについて
ポートフォワーディングってのはつまりポート開放のこと。ルーターは基本的に全てのポートを閉めて外部からのアクセスを止めてるので、一部を開けて(webサーバーなら80) 外部からアクセス出来るようにするということだ。
今回は最初にwebサーバーようにTCP80を開けてapacheのデフォルトページが表示されればOK。
手順としては (バッファロー製ルーターの場合)
- ルーターにログイン(デフォルトゲートウェイのIPアドレス)
- Internet/LANタブ→アドレス変換にチェック
- ゲーム&アプリタブ→ポート変換で項目を埋め(Internte側IPアドレス:エアステーションのInternet側IPアドレス、プロトコル:TCP80、LAN側IPアドレス:サーバーのローカルIP)→新規追加
ポート開放なんてそんなに難しいものではないのでさくっと終わるかとおもいきや…80に接続出来ない!
色々やってみたけどやっぱり出来ない。ふと気づいてtracertでグーグルまでの経路を調べてみると…。
192.168...
192.168...
に、二重ルーター…
今までずっと二重ルーターになってたんですねー。これはいかん。
バッファロー製の無線付きルーターを使ってたのだが、NTTのひかり電話用のルーターも有効化されていた。
これではいくらバッファローのほうのポートを開けてもNTTがブロックしてしまう。
ということでNTTのほうをブリッジモードにして解決。