SlideShare a Scribd company logo
1 of 26
Download to read offline
アニメーション
 / 各種テスト
2012/03/21(水)@PRO&BSC
         樋口 祐紀
 (higuchi_yuki@probsc.jp)
本日の内容
• アニメーション
 –User eXperience を高めましょう
  • 楽しい感じに
  • 処理待ちのイライラを軽減

• 各種テスト
 –単体/結合/安定化試験を自動化し、
  アプリの品質を高めましょう
                            2
アニメーション
    クラス名                   概要
 AlphaAnimation    フェードイン/アウト
 RotateAnimation   回転
 ScaleAnimation    拡大/縮小
TranslateAnimation 移動
  AnimationSet     アニメーションの合成
サンプルのレイアウト
<?xml version="1.0" encoding="utf-8"?>                     main.xml
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:gravity="center">

<Button
  android:layout_width="wrap_content"
  android:padding="20dp"
  android:id="@+id/button"
  android:layout_height="wrap_content"
  android:text="Hello World !!" />

</LinearLayout>



                                                                      4
AlphaAnimation: フェードイン/アウト
public class MainActivity extends Activity {
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
        Button btn = (Button)findViewById(R.id.button);
        btn.setOnClickListener(new OnClickListener() {
           public void onClick(View v) {
               AlphaAnimation alpha =
                     new AlphaAnimation(1.0f, 0.0f);
               alpha.setDuration(3000);
               v.startAnimation(alpha);
           }
        });
    }
}                                                         5
RotateAnimation: 回転
RotateAnimation rotate = new RotateAnimation(
      0, 360, v.getWidth() / 2, v.getHeight() / 2);
rotate.setDuration(3000);
v.startAnimation(rotate);




     ScaleAnimation: 拡大/縮小
ScaleAnimation scale = new ScaleAnimation(
      1, 2, 1, 2, v.getWidth() / 2, v.getHeight() / 2);
scale.setDuration(3000);
scale.setInterpolator(new CycleInterpolator(3));
v.startAnimation(scale);
                                                          6
TranslateAnimation: 移動
TranslateAnimation translate = new TranslateAnimation(
      -10, 10, -10, 10);
translate.setDuration(3000);
translate.setInterpolator(new CycleInterpolator(3));
v.startAnimation(translate);


  AnimationSet: アニメーションの合成
AnimationSet set = new AnimationSet(true);
set.addAnimation(alpha);
set.addAnimation(rotate);    これまでのアニメーションの定
set.addAnimation(scale);     義 部 分 ( startAnimation
v.startAnimation(set);       以外)を残しておき、それらの
                               定義の下に書いてみましょう
                                                         7
アニメーションを利用したビューア
• APK
  – http://goo.gl/LLYXP
• ソース
  – http://goo.gl/oWcyG
• ソースのインポート方法
  – Eclipse の [ファイル(F)] – [インポート
    (I)...] から「インポート」ダイアログを開く
  – [一般] - [既存プロジェクトをワークスペー
    スへ] を選び、「ルート・ディレクトリーの選
    択」にてインポート対象フォルダを選択して
    取り込み完了                         8
Tips: メニューの追加方法
/** メニューID (バージョン) */
static final int MENU_ID_MENU1 = (Menu.FIRST + 1);

public boolean onCreateOptionsMenu(Menu menu) {
  // メニュー (バージョン) の追加
  MenuItem menuVersion = menu.add(
      Menu.NONE, MENU_ID_MENU1, Menu.NONE, "バージョン");
  menuVersion.setIcon(android.R.drawable.ic_menu_info_details);

    return super.onCreateOptionsMenu(menu);
}

public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
      case MENU_ID_MENU1: // バージョン表示
         showDialog(DIALOG_ID_VERSION);
         break;

        default:
           return super.onOptionsItemSelected(item);
    }

    return true;
}
                                                                  9
Tips: ハードウェアキーの補足
public boolean onKeyDown(int keyCode, KeyEvent event) {
  super.onKeyDown(keyCode, event);
    switch (keyCode) {
      case KeyEvent.KEYCODE_VOLUME_DOWN:
      case KeyEvent.KEYCODE_DPAD_DOWN:
      case KeyEvent.KEYCODE_DPAD_RIGHT:
      case KeyEvent.KEYCODE_SPACE:
      case KeyEvent.KEYCODE_ENTER:
          ... (省略) ...
          return true;
        case   KeyEvent.KEYCODE_VOLUME_UP:
        case   KeyEvent.KEYCODE_DPAD_UP:
        case   KeyEvent.KEYCODE_DPAD_LEFT:
        case   KeyEvent.KEYCODE_DEL:
          ... (省略) ...
          return true;
    }
    return false;
}
                                                          10
Tips: 回転後も消えないダイアログ
/** ダイアログID (バージョン) */
static final int DIALOG_ID_VERSION = 0;
protected Dialog onCreateDialog(int id) {
   Dialog dialog;
    switch (id) {
      case DIALOG_ID_VERSION:
         AlertDialog.Builder builder = new AlertDialog.Builder(this);
         builder.setIcon(R.drawable.icon);
         builder.setTitle("イメージビューア");
         builder.setMessage("version 3.0");
         builder.setPositiveButton("OK", null);
         dialog = builder.create();
         break;                       onCreateDialogを経由して表示するこ
                                    とでダイアログのライフサイクルをActivity
        default:
           dialog = null;
                                    に管理してもらうことになります。
    }                               このため、正確に書くと「(画面の)回転後
                                    も消えない」ではなく、「(画面の)回転後
    return dialog;                  にActivityの再生成に伴ってダイアログ
}
                                    も再生成される」が正しくなります。
    ... (省略) ...
    showDialog(DIALOG_ID_VERSION);
                                                                        11
Tips: FrameLayout の使い方
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="@android:color/white"
  android:padding="10dp" >
  <ImageView
    android:id="@+id/imgView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"     アンカーを明示しないと
    android:src="@drawable/img01" />         左上に配置されます
  <Button
    android:id="@+id/btnLeft"
    android:layout_width="100dp"
    android:layout_height="wrap_content"
     android:layout_gravity="bottom|left"
     android:text="←"                       どこにアンカーを置くか
     android:textSize="24sp" />             がポイントになります
  ... (省略) ...

                                                                          12
各種テスト
                  ツール                                  概要

    junit.framework.TestCase                    ①単体試験
                                                (主な対象: ロジック)


android.test.ActivityInstrumentationTestCase2   ②結合試験
                                                (主な対象: UI)


           Monkey Runner                        ③安定化試験
                                                (主な対象: メモリリーク)
テストプロジェクトの追加
• Androidプロジェクト作成時に追加できます




                            14
サンプル(SimpleCalc)の用意①
<?xml version="1.0" encoding="utf-8"?>                   <Button
<LinearLayout xmlns:android=                                android:id="@+id/btnMul"
     "http://schemas.android.com/apk/res/android"           android:layout_width="fill_parent"
  android:layout_width="wrap_content"                       android:layout_height="wrap_content"
  android:layout_height="wrap_content"                      android:text="×"
  android:layout_gravity="center_horizontal"                android:textSize="22sp" />
  android:orientation="horizontal" >                     <Button
  <EditText                                                 android:id="@+id/btnDiv"
     android:id="@+id/editNum1"                             android:layout_width="fill_parent"
     android:layout_width="68dp"                            android:layout_height="wrap_content"
     android:layout_height="wrap_content"                   android:text="÷"
     android:layout_gravity="center_vertical"               android:textSize="22sp" />
     android:gravity="center"                         </LinearLayout>
     android:inputType="number" />                    <EditText
  <LinearLayout                                          android:id="@+id/editNum2"
     android:layout_width="48dp"                         android:layout_width="68dp"
     android:layout_height="wrap_content"                android:layout_height="wrap_content"
     android:orientation="vertical" >                    android:layout_gravity="center_vertical"
     <Button                                             android:gravity="center"
        android:id="@+id/btnAdd"                         android:inputType="number" />
        android:layout_width="fill_parent"            <TextView
        android:layout_height="wrap_content"             android:layout_width="48dp"
        android:text="+"                                 android:layout_height="wrap_content"
        android:textSize="22sp" />                       android:layout_gravity="center_vertical"
      <Button                                            android:gravity="center"
        android:id="@+id/btnSub"                         android:text="="
        android:layout_width="fill_parent"               android:textSize="22sp" />
        android:layout_height="wrap_content"          <EditText
        android:text="-"                                 android:id="@+id/editAnswer"
        android:textSize="22sp" />                       android:layout_width="68dp"
                                                         android:layout_height="wrap_content"
                                                         android:layout_gravity="center_vertical"
                                                         android:editable="false"
                                                         android:gravity="center" />
・res/layout/main.xml                                </LinearLayout>
                                                                                                    15
サンプル(SimpleCalc)の用意②
package jp.probsc.simplecalc;
                                               ・src/.../Calculator.java
/**
 *計算クラス
 */
public class Calculator {
  /** 足し算 */
  public static int Add(int a, int b) {
      return a + b;
  }
    /** 引き算 */
    public static int Sub(int a, int b) {
      return a - b;
    }
    /** 掛け算 */
    public static int Mul(int a, int b) {
      return a * b;
    }
    /** 割り算 */
    public static double Div(int a, int b) {
      return a / b;
    }
}                                                                   16
サンプル(SimpleCalc)の用意③
package jp.probsc.simplecalc;                                  final EditText num2 =
                                                                  (EditText)findViewById(R.id.editNum2);
import   android.app.Activity;                                 num2.setSelectAllOnFocus(true);
import   android.os.Bundle;
import   android.view.View;                                    final EditText numAnswer =
import   android.view.View.OnClickListener;                       (EditText)findViewById(R.id.editAnswer);
import   android.widget.Button;
import   android.widget.EditText;                              Button btnAdd =
                                                                  (Button)findViewById(R.id.btnAdd);
/**                                                            btnAdd.setOnClickListener(new OnClickListener() {
 * シンプル電卓クラス                                                      public void onClick(View v) {
 */                                                                 int ret = Calculator.Add(
public class MainActivity extends Activity {                            escape(num1), escape(num2));
   /**                                                              numAnswer.setText(String.valueOf(ret));
    * onCreate コールバックメソッド                                         }
    */                                                         });
   public void onCreate(Bundle savedInstanceState) {       }
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);                       /**
                                                            * EditText をエスケープして整数値を返す
      // ウィジェットの初期化                                         *
      init();                                               * @param target エスケープ対象の EditText ウィジェット
  }                                                         * @return 整数値
                                                            */
  /**                                                      public static int escape(EditText target) {
   * ウィジェットの初期化                                               try {
   */                                                            return Integer.parseInt(target.getText().toString());
  private void init() {                                       } catch (Exception ex) {
     final EditText num1 =                                       target.setText("0");
        (EditText)findViewById(R.id.editNum1);                   return 0;
     num1.setSelectAllOnFocus(true);                          }
                                                           }
・src/.../MainActivity.java                             }
                                                                                                                17
サンプル(SimpleCalc)の完成
        • ソース
         – サンプルプロジェクト
            • http://goo.gl/SQ0LW
         – テストプロジェクト
            • http://goo.gl/KM1bW


        • この四則演算を行うアプリの
          テストを行います。試験は下
          記の4種類です
         – ① 単体試験
         – ② 結合試験
         – ③ 安定化試験
                                18
①単体試験

          単体試験の準備
 • ロジックを試験します
   – テストプロジェクトに「CalculatorTest.java」を追加
              package jp.probsc.simplecalc.test;

              import jp.probsc.simplecalc.Calculator;
              import junit.framework.TestCase;

              public class CalculatorTest extends TestCase {
                public void testAdd() {
                    assertEquals(0, Calculator.Add(0, 0));
                    assertEquals(1, Calculator.Add(1, 0));
                    assertEquals(2, Calculator.Add(2, 0));
                    assertEquals(1, Calculator.Add(0, 1));
                    assertEquals(2, Calculator.Add(0, 2));
                    assertEquals(2, Calculator.Add(1, 1));
                    assertEquals(4, Calculator.Add(2, 2));
                }
              }
                                                               19
①単体試験

            単体試験の実施
 • クラスを右クリックし、[実行(R)]-[Android JUnit Test]を実行




  1つでもパスしないテストケース
  があると、バーが赤色になります
 テスト実施はテストケース(メソッ
 ド)ごと、クラスごと、プロジェクトご
  との単位にて実施できます。


                                                20
②結合試験

                            結合試験の準備
   • UIを試験します                        ※テストプロジェクトに「MainActivityTest.java」を追加
package jp.probsc.simplecalc.test;                                 getInstrumentation()
                                                                      .waitForIdleSync();
import   android.test.ActivityInstrumentationTestCase2;            getActivity().runOnUiThread(
import   android.widget.Button;                                                      new Runnable() {
import   android.widget.EditText;                                     public void run() {
import   jp.probsc.simplecalc.MainActivity;                             num1.setText("2");
                                                                        num2.setText("4");
public class MainActivityTest extends                                   btnAdd.performClick();
  ActivityInstrumentationTestCase2<MainActivity> {                    }
  public MainActivityTest() {                                      });
      super(MainActivity.class);
  }                                                                 getInstrumentation()
                                                                       .waitForIdleSync();
  public void testCalc() {                                          EditText numAnswer = (EditText)
    final EditText num1 =                                              getActivity().findViewById(
        (EditText)getActivity().findViewById(                     jp.probsc.simplecalc.R.id.editAnswer);
           jp.probsc.simplecalc.R.id.editNum1);                     assertEquals("6",
    final EditText num2 =                                               numAnswer.getText().toString());
        (EditText)getActivity().findViewById(                 }
           jp.probsc.simplecalc.R.id.editNum2);           }
    final Button btnAdd =
        (Button)getActivity().findViewById(
           jp.probsc.simplecalc.R.id.btnAdd);                                                      21
②結合試験

           結合試験の実施
 • テ ス ト プ ロ ジ ェ ク ト を 選 択 し て [ 実 行 (R)]-
   [Android JUnit Test] を実行することで、先
   ほどの単体試験と同時にテストを実施できます




   UIのテストは実機、またはエ
   ミュレータ上で実行されます。
                                         22
③安定化試験

               Monkey Runner の利用
                                                         # テストの実施
#!/usr/bin/python
# coding: UTF-8                                          def doTest():
                                                                                   mr_simplecalc.py
                                                             device = init()
from com.android.monkeyrunner import MonkeyRunner,
MonkeyDevice                                                snapshot(device)   Pythonスクリプトです
import datetime
                                                            for i in range(1, 1001):
# 日時文字列の取得                                                      printMsg('cnt: %d' % i)
def getDate():
    d = datetime.datetime.today()                               # 1つめの数値を入力
    return d.strftime('%Y%m%d_%H%M%S')                          MonkeyRunner.sleep(1)
                                                                device.touch(65, 215, 'DOWN_AND_UP')
# スナップショットの取得                                                   device.type('%d' % i)
# (monkeyrunner.bat と同階層に snapshot フォルダを準備のこと)
def snapshot(device):                                           # 2つめの数値を入力
    MonkeyRunner.sleep(1)                                       MonkeyRunner.sleep(1)
    result = device.takeSnapshot()                              device.touch(240, 215, 'DOWN_AND_UP')
    result.writeToFile(                                         num = i * 2
        'snapshot/%s.png' % getDate(), 'png')                   device.type('%d' % num)

# テスト初期化                                                        # 「+」ボタンを押下
def init():                                                     MonkeyRunner.sleep(1)
    device = MonkeyRunner.waitForConnection()                   device.touch(155, 110, 'DOWN_AND_UP')
    device.startActivity(
       component='jp.probsc.simplecalc/.MainActivity')          snapshot(device)
    return device
                                                         # テストの開始
# 標準出力へメッセージを出力                                          printMsg('test start.')
def printMsg(msg):                                       doTest()
    print '[%s] %s' % (getDate(), msg)                   printMsg('test end.')                   23
③安定化試験

      Monkey Runner の実行結果
・コマンドプロンプトに下記コマンドを入力してMonkey Runnerを起動します
c:¥>
c:¥>C:¥android¥android-sdk-windows¥tools¥monkeyrunner.bat C:¥mr_simplecalc.py
[20120318_145102] test start.
[20120318_145117] cnt: 1
[20120318_145132] cnt: 2       今回のスクリプトの場合、1000回の足し算が
[20120318_145148] cnt: 3       自動的に実行されます。別途、メモリ使用状
[20120318_145201] cnt: 4
[20120318_145215] cnt: 5        況などを監視してアプリの安定化を図ります
...

・monkeryrunner.bat と同階層の snapshot フォルダに下記が保存されます




                                                                           24
よりテストを実施しやすくするために
• 今回ご紹介したUIテストとMonkey Runnerで
  は、ウィジェットのIDや画面上の座標を知っている
  必要があり、「OKボタンを押す」などの直観的な
  テストをかけない...
 NativeDriver や Scirocco などのツールの利用が便利です!


• これまでJavaのプロジェクトではもっくオブジェクト
  を使って試験を行えたが、AndroidはVMが異な
  るため、既存ツールを利用できない...
   EasyMock の知識を Android Mock に活かせます!
                                           25
本日の課題
• イメージビューアの改善
 – 縦画面と横画面のそれぞれに異なる1つ以上のアニ
   メーションを追加しましょう
 – メニューに1つ以上の独自の機能を追加しましょう
• SimpleCalc とテストの改善
 – SimpleCalc に足し算以外の機能を追加しましょう
 – テストプロジェクトに足し算以外の機能のテストケース
   を追加しましょう
                                  26

More Related Content

Similar to Android Lecture #04 @PRO&BSC Inc.

Android Architecture Componentsの新機能
Android Architecture Componentsの新機能Android Architecture Componentsの新機能
Android Architecture Componentsの新機能Damper Matsu
 
学生向けAndroid勉強会(入門編)
学生向けAndroid勉強会(入門編)学生向けAndroid勉強会(入門編)
学生向けAndroid勉強会(入門編)Itsuki Kuroda
 
Jqm20120210
Jqm20120210Jqm20120210
Jqm20120210cmtomoda
 
Pf部2012年1月勉強会.androidsola
Pf部2012年1月勉強会.androidsolaPf部2012年1月勉強会.androidsola
Pf部2012年1月勉強会.androidsolaandroid sola
 
Titanium Mobile
Titanium MobileTitanium Mobile
Titanium MobileNaoya Ito
 
Head First XML Layout on Android
Head First XML Layout on AndroidHead First XML Layout on Android
Head First XML Layout on AndroidYuki Anzai
 
Android Lecture #02 @PRO&BSC Inc.
Android Lecture #02 @PRO&BSC Inc.Android Lecture #02 @PRO&BSC Inc.
Android Lecture #02 @PRO&BSC Inc.Yuki Higuchi
 
はじめてのAndroid開発
はじめてのAndroid開発はじめてのAndroid開発
はじめてのAndroid開発Katsumi Honda
 
Web1.0のハイブリッドアプリ開発
Web1.0のハイブリッドアプリ開発Web1.0のハイブリッドアプリ開発
Web1.0のハイブリッドアプリ開発Kenta Tsuji
 
デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)
デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)
デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)Chihiro Tomita
 
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会Jumpei Ogawa
 
夜子まま塾講義10(画面の呼び出し)
夜子まま塾講義10(画面の呼び出し)夜子まま塾講義10(画面の呼び出し)
夜子まま塾講義10(画面の呼び出し)Masafumi Terazono
 
Android Lecture #01 @PRO&BSC Inc.
Android Lecture #01 @PRO&BSC Inc.Android Lecture #01 @PRO&BSC Inc.
Android Lecture #01 @PRO&BSC Inc.Yuki Higuchi
 
cocos2d-xにおけるBox2Dの利用方法および便利なツール
cocos2d-xにおけるBox2Dの利用方法および便利なツールcocos2d-xにおけるBox2Dの利用方法および便利なツール
cocos2d-xにおけるBox2Dの利用方法および便利なツールTomoaki Shimizu
 
初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)
初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)
初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)Masafumi Terazono
 
Azure IoT Edge で Custom Vision
Azure IoT Edge で Custom VisionAzure IoT Edge で Custom Vision
Azure IoT Edge で Custom VisionYoshitaka Seo
 
Jetpack Composeのパフォーマンスの基本
Jetpack Composeのパフォーマンスの基本Jetpack Composeのパフォーマンスの基本
Jetpack Composeのパフォーマンスの基本Damper Matsu
 
20150425 DroidKaigi つかえるGradleプロジェクトの作り方
20150425 DroidKaigi つかえるGradleプロジェクトの作り方20150425 DroidKaigi つかえるGradleプロジェクトの作り方
20150425 DroidKaigi つかえるGradleプロジェクトの作り方Makoto Yamazaki
 
日本Androidの会 中国支部資料
日本Androidの会 中国支部資料日本Androidの会 中国支部資料
日本Androidの会 中国支部資料Masafumi Terazono
 

Similar to Android Lecture #04 @PRO&BSC Inc. (20)

Android Architecture Componentsの新機能
Android Architecture Componentsの新機能Android Architecture Componentsの新機能
Android Architecture Componentsの新機能
 
学生向けAndroid勉強会(入門編)
学生向けAndroid勉強会(入門編)学生向けAndroid勉強会(入門編)
学生向けAndroid勉強会(入門編)
 
Jqm20120210
Jqm20120210Jqm20120210
Jqm20120210
 
Pf部2012年1月勉強会.androidsola
Pf部2012年1月勉強会.androidsolaPf部2012年1月勉強会.androidsola
Pf部2012年1月勉強会.androidsola
 
Titanium Mobile
Titanium MobileTitanium Mobile
Titanium Mobile
 
Head First XML Layout on Android
Head First XML Layout on AndroidHead First XML Layout on Android
Head First XML Layout on Android
 
Android Lecture #02 @PRO&BSC Inc.
Android Lecture #02 @PRO&BSC Inc.Android Lecture #02 @PRO&BSC Inc.
Android Lecture #02 @PRO&BSC Inc.
 
はじめてのAndroid開発
はじめてのAndroid開発はじめてのAndroid開発
はじめてのAndroid開発
 
Web1.0のハイブリッドアプリ開発
Web1.0のハイブリッドアプリ開発Web1.0のハイブリッドアプリ開発
Web1.0のハイブリッドアプリ開発
 
デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)
デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)
デザイナーが実際にAndroidアプリのレイアウトを 組んでみた(秋葉ちひろ)
 
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
 
夜子まま塾講義10(画面の呼び出し)
夜子まま塾講義10(画面の呼び出し)夜子まま塾講義10(画面の呼び出し)
夜子まま塾講義10(画面の呼び出し)
 
Android Lecture #01 @PRO&BSC Inc.
Android Lecture #01 @PRO&BSC Inc.Android Lecture #01 @PRO&BSC Inc.
Android Lecture #01 @PRO&BSC Inc.
 
cocos2d-xにおけるBox2Dの利用方法および便利なツール
cocos2d-xにおけるBox2Dの利用方法および便利なツールcocos2d-xにおけるBox2Dの利用方法および便利なツール
cocos2d-xにおけるBox2Dの利用方法および便利なツール
 
Android Wear Apps
Android Wear AppsAndroid Wear Apps
Android Wear Apps
 
初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)
初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)
初心者〜中級者 Android StudioによるAndroid勉強会資料(スライド)
 
Azure IoT Edge で Custom Vision
Azure IoT Edge で Custom VisionAzure IoT Edge で Custom Vision
Azure IoT Edge で Custom Vision
 
Jetpack Composeのパフォーマンスの基本
Jetpack Composeのパフォーマンスの基本Jetpack Composeのパフォーマンスの基本
Jetpack Composeのパフォーマンスの基本
 
20150425 DroidKaigi つかえるGradleプロジェクトの作り方
20150425 DroidKaigi つかえるGradleプロジェクトの作り方20150425 DroidKaigi つかえるGradleプロジェクトの作り方
20150425 DroidKaigi つかえるGradleプロジェクトの作り方
 
日本Androidの会 中国支部資料
日本Androidの会 中国支部資料日本Androidの会 中国支部資料
日本Androidの会 中国支部資料
 

Recently uploaded

The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024koheioishi1
 
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライドリアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライドKen Fukui
 
TEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdfTEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdfyukisuga3
 
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライドリアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライドKen Fukui
 
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライドリアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライドKen Fukui
 
ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学
ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学
ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学ssusere0a682
 
UniProject Workshop Make a Discord Bot with JavaScript
UniProject Workshop Make a Discord Bot with JavaScriptUniProject Workshop Make a Discord Bot with JavaScript
UniProject Workshop Make a Discord Bot with JavaScriptyuitoakatsukijp
 
TokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentationTokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentationYukiTerazawa
 
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライドリアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライドKen Fukui
 
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライドリアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライドKen Fukui
 

Recently uploaded (10)

The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024The_Five_Books_Overview_Presentation_2024
The_Five_Books_Overview_Presentation_2024
 
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライドリアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
 
TEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdfTEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdf
 
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライドリアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
 
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライドリアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
 
ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学
ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学
ゲーム理論 BASIC 演習105 -n人囚人のジレンマモデル- #ゲーム理論 #gametheory #数学
 
UniProject Workshop Make a Discord Bot with JavaScript
UniProject Workshop Make a Discord Bot with JavaScriptUniProject Workshop Make a Discord Bot with JavaScript
UniProject Workshop Make a Discord Bot with JavaScript
 
TokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentationTokyoTechGraduateExaminationPresentation
TokyoTechGraduateExaminationPresentation
 
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライドリアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
 
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライドリアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
 

Android Lecture #04 @PRO&BSC Inc.

  • 2. 本日の内容 • アニメーション –User eXperience を高めましょう • 楽しい感じに • 処理待ちのイライラを軽減 • 各種テスト –単体/結合/安定化試験を自動化し、 アプリの品質を高めましょう 2
  • 3. アニメーション クラス名 概要 AlphaAnimation フェードイン/アウト RotateAnimation 回転 ScaleAnimation 拡大/縮小 TranslateAnimation 移動 AnimationSet アニメーションの合成
  • 4. サンプルのレイアウト <?xml version="1.0" encoding="utf-8"?> main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center"> <Button android:layout_width="wrap_content" android:padding="20dp" android:id="@+id/button" android:layout_height="wrap_content" android:text="Hello World !!" /> </LinearLayout> 4
  • 5. AlphaAnimation: フェードイン/アウト public class MainActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btn = (Button)findViewById(R.id.button); btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { AlphaAnimation alpha = new AlphaAnimation(1.0f, 0.0f); alpha.setDuration(3000); v.startAnimation(alpha); } }); } } 5
  • 6. RotateAnimation: 回転 RotateAnimation rotate = new RotateAnimation( 0, 360, v.getWidth() / 2, v.getHeight() / 2); rotate.setDuration(3000); v.startAnimation(rotate); ScaleAnimation: 拡大/縮小 ScaleAnimation scale = new ScaleAnimation( 1, 2, 1, 2, v.getWidth() / 2, v.getHeight() / 2); scale.setDuration(3000); scale.setInterpolator(new CycleInterpolator(3)); v.startAnimation(scale); 6
  • 7. TranslateAnimation: 移動 TranslateAnimation translate = new TranslateAnimation( -10, 10, -10, 10); translate.setDuration(3000); translate.setInterpolator(new CycleInterpolator(3)); v.startAnimation(translate); AnimationSet: アニメーションの合成 AnimationSet set = new AnimationSet(true); set.addAnimation(alpha); set.addAnimation(rotate); これまでのアニメーションの定 set.addAnimation(scale); 義 部 分 ( startAnimation v.startAnimation(set); 以外)を残しておき、それらの 定義の下に書いてみましょう 7
  • 8. アニメーションを利用したビューア • APK – http://goo.gl/LLYXP • ソース – http://goo.gl/oWcyG • ソースのインポート方法 – Eclipse の [ファイル(F)] – [インポート (I)...] から「インポート」ダイアログを開く – [一般] - [既存プロジェクトをワークスペー スへ] を選び、「ルート・ディレクトリーの選 択」にてインポート対象フォルダを選択して 取り込み完了 8
  • 9. Tips: メニューの追加方法 /** メニューID (バージョン) */ static final int MENU_ID_MENU1 = (Menu.FIRST + 1); public boolean onCreateOptionsMenu(Menu menu) { // メニュー (バージョン) の追加 MenuItem menuVersion = menu.add( Menu.NONE, MENU_ID_MENU1, Menu.NONE, "バージョン"); menuVersion.setIcon(android.R.drawable.ic_menu_info_details); return super.onCreateOptionsMenu(menu); } public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ID_MENU1: // バージョン表示 showDialog(DIALOG_ID_VERSION); break; default: return super.onOptionsItemSelected(item); } return true; } 9
  • 10. Tips: ハードウェアキーの補足 public boolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event); switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_SPACE: case KeyEvent.KEYCODE_ENTER: ... (省略) ... return true; case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DEL: ... (省略) ... return true; } return false; } 10
  • 11. Tips: 回転後も消えないダイアログ /** ダイアログID (バージョン) */ static final int DIALOG_ID_VERSION = 0; protected Dialog onCreateDialog(int id) { Dialog dialog; switch (id) { case DIALOG_ID_VERSION: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(R.drawable.icon); builder.setTitle("イメージビューア"); builder.setMessage("version 3.0"); builder.setPositiveButton("OK", null); dialog = builder.create(); break; onCreateDialogを経由して表示するこ とでダイアログのライフサイクルをActivity default: dialog = null; に管理してもらうことになります。 } このため、正確に書くと「(画面の)回転後 も消えない」ではなく、「(画面の)回転後 return dialog; にActivityの再生成に伴ってダイアログ } も再生成される」が正しくなります。 ... (省略) ... showDialog(DIALOG_ID_VERSION); 11
  • 12. Tips: FrameLayout の使い方 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/white" android:padding="10dp" > <ImageView android:id="@+id/imgView" android:layout_width="fill_parent" android:layout_height="fill_parent" アンカーを明示しないと android:src="@drawable/img01" /> 左上に配置されます <Button android:id="@+id/btnLeft" android:layout_width="100dp" android:layout_height="wrap_content" android:layout_gravity="bottom|left" android:text="←" どこにアンカーを置くか android:textSize="24sp" /> がポイントになります ... (省略) ... 12
  • 13. 各種テスト ツール 概要 junit.framework.TestCase ①単体試験 (主な対象: ロジック) android.test.ActivityInstrumentationTestCase2 ②結合試験 (主な対象: UI) Monkey Runner ③安定化試験 (主な対象: メモリリーク)
  • 15. サンプル(SimpleCalc)の用意① <?xml version="1.0" encoding="utf-8"?> <Button <LinearLayout xmlns:android= android:id="@+id/btnMul" "http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_height="wrap_content" android:text="×" android:layout_gravity="center_horizontal" android:textSize="22sp" /> android:orientation="horizontal" > <Button <EditText android:id="@+id/btnDiv" android:id="@+id/editNum1" android:layout_width="fill_parent" android:layout_width="68dp" android:layout_height="wrap_content" android:layout_height="wrap_content" android:text="÷" android:layout_gravity="center_vertical" android:textSize="22sp" /> android:gravity="center" </LinearLayout> android:inputType="number" /> <EditText <LinearLayout android:id="@+id/editNum2" android:layout_width="48dp" android:layout_width="68dp" android:layout_height="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > android:layout_gravity="center_vertical" <Button android:gravity="center" android:id="@+id/btnAdd" android:inputType="number" /> android:layout_width="fill_parent" <TextView android:layout_height="wrap_content" android:layout_width="48dp" android:text="+" android:layout_height="wrap_content" android:textSize="22sp" /> android:layout_gravity="center_vertical" <Button android:gravity="center" android:id="@+id/btnSub" android:text="=" android:layout_width="fill_parent" android:textSize="22sp" /> android:layout_height="wrap_content" <EditText android:text="-" android:id="@+id/editAnswer" android:textSize="22sp" /> android:layout_width="68dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:editable="false" android:gravity="center" /> ・res/layout/main.xml </LinearLayout> 15
  • 16. サンプル(SimpleCalc)の用意② package jp.probsc.simplecalc; ・src/.../Calculator.java /** *計算クラス */ public class Calculator { /** 足し算 */ public static int Add(int a, int b) { return a + b; } /** 引き算 */ public static int Sub(int a, int b) { return a - b; } /** 掛け算 */ public static int Mul(int a, int b) { return a * b; } /** 割り算 */ public static double Div(int a, int b) { return a / b; } } 16
  • 17. サンプル(SimpleCalc)の用意③ package jp.probsc.simplecalc; final EditText num2 = (EditText)findViewById(R.id.editNum2); import android.app.Activity; num2.setSelectAllOnFocus(true); import android.os.Bundle; import android.view.View; final EditText numAnswer = import android.view.View.OnClickListener; (EditText)findViewById(R.id.editAnswer); import android.widget.Button; import android.widget.EditText; Button btnAdd = (Button)findViewById(R.id.btnAdd); /** btnAdd.setOnClickListener(new OnClickListener() { * シンプル電卓クラス public void onClick(View v) { */ int ret = Calculator.Add( public class MainActivity extends Activity { escape(num1), escape(num2)); /** numAnswer.setText(String.valueOf(ret)); * onCreate コールバックメソッド } */ }); public void onCreate(Bundle savedInstanceState) { } super.onCreate(savedInstanceState); setContentView(R.layout.main); /** * EditText をエスケープして整数値を返す // ウィジェットの初期化 * init(); * @param target エスケープ対象の EditText ウィジェット } * @return 整数値 */ /** public static int escape(EditText target) { * ウィジェットの初期化 try { */ return Integer.parseInt(target.getText().toString()); private void init() { } catch (Exception ex) { final EditText num1 = target.setText("0"); (EditText)findViewById(R.id.editNum1); return 0; num1.setSelectAllOnFocus(true); } } ・src/.../MainActivity.java } 17
  • 18. サンプル(SimpleCalc)の完成 • ソース – サンプルプロジェクト • http://goo.gl/SQ0LW – テストプロジェクト • http://goo.gl/KM1bW • この四則演算を行うアプリの テストを行います。試験は下 記の4種類です – ① 単体試験 – ② 結合試験 – ③ 安定化試験 18
  • 19. ①単体試験 単体試験の準備 • ロジックを試験します – テストプロジェクトに「CalculatorTest.java」を追加 package jp.probsc.simplecalc.test; import jp.probsc.simplecalc.Calculator; import junit.framework.TestCase; public class CalculatorTest extends TestCase { public void testAdd() { assertEquals(0, Calculator.Add(0, 0)); assertEquals(1, Calculator.Add(1, 0)); assertEquals(2, Calculator.Add(2, 0)); assertEquals(1, Calculator.Add(0, 1)); assertEquals(2, Calculator.Add(0, 2)); assertEquals(2, Calculator.Add(1, 1)); assertEquals(4, Calculator.Add(2, 2)); } } 19
  • 20. ①単体試験 単体試験の実施 • クラスを右クリックし、[実行(R)]-[Android JUnit Test]を実行 1つでもパスしないテストケース があると、バーが赤色になります テスト実施はテストケース(メソッ ド)ごと、クラスごと、プロジェクトご との単位にて実施できます。 20
  • 21. ②結合試験 結合試験の準備 • UIを試験します ※テストプロジェクトに「MainActivityTest.java」を追加 package jp.probsc.simplecalc.test; getInstrumentation() .waitForIdleSync(); import android.test.ActivityInstrumentationTestCase2; getActivity().runOnUiThread( import android.widget.Button; new Runnable() { import android.widget.EditText; public void run() { import jp.probsc.simplecalc.MainActivity; num1.setText("2"); num2.setText("4"); public class MainActivityTest extends btnAdd.performClick(); ActivityInstrumentationTestCase2<MainActivity> { } public MainActivityTest() { }); super(MainActivity.class); } getInstrumentation() .waitForIdleSync(); public void testCalc() { EditText numAnswer = (EditText) final EditText num1 = getActivity().findViewById( (EditText)getActivity().findViewById( jp.probsc.simplecalc.R.id.editAnswer); jp.probsc.simplecalc.R.id.editNum1); assertEquals("6", final EditText num2 = numAnswer.getText().toString()); (EditText)getActivity().findViewById( } jp.probsc.simplecalc.R.id.editNum2); } final Button btnAdd = (Button)getActivity().findViewById( jp.probsc.simplecalc.R.id.btnAdd); 21
  • 22. ②結合試験 結合試験の実施 • テ ス ト プ ロ ジ ェ ク ト を 選 択 し て [ 実 行 (R)]- [Android JUnit Test] を実行することで、先 ほどの単体試験と同時にテストを実施できます UIのテストは実機、またはエ ミュレータ上で実行されます。 22
  • 23. ③安定化試験 Monkey Runner の利用 # テストの実施 #!/usr/bin/python # coding: UTF-8 def doTest(): mr_simplecalc.py device = init() from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice snapshot(device) Pythonスクリプトです import datetime for i in range(1, 1001): # 日時文字列の取得 printMsg('cnt: %d' % i) def getDate(): d = datetime.datetime.today() # 1つめの数値を入力 return d.strftime('%Y%m%d_%H%M%S') MonkeyRunner.sleep(1) device.touch(65, 215, 'DOWN_AND_UP') # スナップショットの取得 device.type('%d' % i) # (monkeyrunner.bat と同階層に snapshot フォルダを準備のこと) def snapshot(device): # 2つめの数値を入力 MonkeyRunner.sleep(1) MonkeyRunner.sleep(1) result = device.takeSnapshot() device.touch(240, 215, 'DOWN_AND_UP') result.writeToFile( num = i * 2 'snapshot/%s.png' % getDate(), 'png') device.type('%d' % num) # テスト初期化 # 「+」ボタンを押下 def init(): MonkeyRunner.sleep(1) device = MonkeyRunner.waitForConnection() device.touch(155, 110, 'DOWN_AND_UP') device.startActivity( component='jp.probsc.simplecalc/.MainActivity') snapshot(device) return device # テストの開始 # 標準出力へメッセージを出力 printMsg('test start.') def printMsg(msg): doTest() print '[%s] %s' % (getDate(), msg) printMsg('test end.') 23
  • 24. ③安定化試験 Monkey Runner の実行結果 ・コマンドプロンプトに下記コマンドを入力してMonkey Runnerを起動します c:¥> c:¥>C:¥android¥android-sdk-windows¥tools¥monkeyrunner.bat C:¥mr_simplecalc.py [20120318_145102] test start. [20120318_145117] cnt: 1 [20120318_145132] cnt: 2 今回のスクリプトの場合、1000回の足し算が [20120318_145148] cnt: 3 自動的に実行されます。別途、メモリ使用状 [20120318_145201] cnt: 4 [20120318_145215] cnt: 5 況などを監視してアプリの安定化を図ります ... ・monkeryrunner.bat と同階層の snapshot フォルダに下記が保存されます 24
  • 25. よりテストを実施しやすくするために • 今回ご紹介したUIテストとMonkey Runnerで は、ウィジェットのIDや画面上の座標を知っている 必要があり、「OKボタンを押す」などの直観的な テストをかけない... NativeDriver や Scirocco などのツールの利用が便利です! • これまでJavaのプロジェクトではもっくオブジェクト を使って試験を行えたが、AndroidはVMが異な るため、既存ツールを利用できない... EasyMock の知識を Android Mock に活かせます! 25
  • 26. 本日の課題 • イメージビューアの改善 – 縦画面と横画面のそれぞれに異なる1つ以上のアニ メーションを追加しましょう – メニューに1つ以上の独自の機能を追加しましょう • SimpleCalc とテストの改善 – SimpleCalc に足し算以外の機能を追加しましょう – テストプロジェクトに足し算以外の機能のテストケース を追加しましょう 26