woensdag 17 juli 2013

RoboLectric with Gradle and Android Studio

Below you will find a small log of trying to run Robolectric on Android studio using the gradle build.

Used sources:
[1] build.gradle file: http://stackoverflow.com/questions/16649397/robolectric-with-gradle-resources-not-found?rq=1
[2] Add jars to Android Studio: http://stackoverflow.com/questions/16881936/android-studio-missing-external-dependencies

Adapting the build.gradle file according to this link on stackoverflow. build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}

repositories {
    mavenCentral()
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
}

apply plugin: 'android'

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 16
    }
}

sourceSets {
    testLocal {
        java.srcDir file('src/test/java')
        resources.srcDir file('src/test/resources')
    }
}

dependencies {
    compile 'org.roboguice:roboguice:2.0'
    compile 'com.google.android:support-v4:r6'


    testLocalCompile 'junit:junit:4.8.2'
    testLocalCompile 'org.robolectric:robolectric:2.1'
    testLocalCompile 'com.google.android:android:4.0.1.2'
    testLocalCompile 'com.google.android:support-v4:r6'
    testLocalCompile 'org.roboguice:roboguice:2.0'
}

task localTest(type: Test, dependsOn: assemble) {
    testClassesDir = sourceSets.testLocal.output.classesDir

    android.sourceSets.main.java.srcDirs.each { dir ->
        def buildDir = dir.getAbsolutePath().split('/')
        buildDir =  (buildDir[0..(buildDir.length - 4)] + ['build', 'classes', 'debug']).join('/')

        sourceSets.testLocal.compileClasspath += files(buildDir)
        sourceSets.testLocal.runtimeClasspath += files(buildDir)
    }

    classpath = sourceSets.testLocal.runtimeClasspath
}

check.dependsOn localTest


This results in a working build using this DummyTest class in src/test/java/...

package org.fhict.calculator.rtest;

import junit.framework.Assert;

import roboguice.test.RobolectricRoboTestRunner;

import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;

import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;


@RunWith(RobolectricTestRunner.class)
public class DummyTest {

    @Before
    public void setUp() {
    }

    @Test
    public void testSomeNumber() {
        Assert.assertEquals(true,true);
    }

}

From command line a build is now running ('gradle localTest' from terminal). Generating a test-report in file:///home/ben/AndroidStudioProjects/CalculatorProject/Calculator/build/reports/tests/org.fhict.calculator.rtest.DummyTest.html




AndroidStudio does not yet recognize the new jar files as defined by testLocalCompile in build.gradle. Manually add them to AndroidStudio using this link.



Remaining open issues:

(1) How to show the output of the Robolectric unit tests in AndroidStudio?
(2) How to force recompile when the RoboLectric unit test has been changed? Now only a gradle clean && gradle localTest. Not so nice...

Please comment if you know how to solve these?

donderdag 11 juli 2013

Android-Studio keyboard shortcuts

Some basic Android-Studio keyboard links:

Shortcut: Meaning:
SHIFT + SPACEAuto completion
ALT + TABShow automatic fix options
CTRL + QShow documentation
CTRL + BGo to declaration of class
SHIFT + F6Go to declaration of class
CTRL + OOverride method
CTRL + IImplement interface
CTRL + ALT + IAuto indent
CTLR + NOpen class
CTLR + SHIFT + NOpen file
CTLR + EOpen recent files
CTLR + WSelect word
CTLR + F4Close file
CTLR + /Put in comment
CTLR + SHIFT + /Uncomment

woensdag 30 maart 2011

Android testing of Activities: first experiments.

Below an initial example of Activity testcase in Android. A first experiment after reading the android development page on Activity Testing.

The GuessPictureActivity is connected to a simple screen containing a TextView and ImageView. When the image is 'Clicked' a name will be displayed. On the next click a new photo will be loaded.



The activity under test is:
package com.ben.android.xmlweb;

import java.util.HashMap;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;

public class GuessPictureActivity extends Activity {
   
    private TextView textFaceName;
    private ImageView imageView;
    private HashMap<String,Integer> drawingsByName;
    private int counter;
    static final String LOGID = "FaceMemory";
    private String names[];
    private Boolean guessed;
               
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        drawingsByName = new HashMap<String, Integer>();               
        drawingsByName.put("Pip", new Integer(R.drawable.pip));
        drawingsByName.put("The Stig", new Integer(R.drawable.stig));
        drawingsByName.put("Tux",new Integer(R.drawable.tux));
        names = new String[drawingsByName.size()];
        drawingsByName.keySet().toArray(names);
        counter = 0;
        guessed = false;
               
        textFaceName = (TextView)findViewById(R.id.textFaceName);       
        imageView= (ImageView)findViewById(R.id.imageView);
       
        imageView.setOnClickListener( new OnClickListener() {
            @Override
            public void onClick(View v) {   
                if(!guessed) {
                    textFaceName.setText(names[counter]);
                    guessed = true;
                } else {
                    counter++;
                    if(counter>=names.length) counter = 0;
                    imageView.setImageResource(drawingsByName.get(names[counter]));
                    textFaceName.setText(R.string.textGuessName);
                    guessed = false;
                }                           
            }
        });
    }
}


The activity test case looks like: 
package com.ben.android.xmlweb.test;

import com.ben.android.xmlweb.GuessPictureActivity;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.widget.ImageView;
import android.widget.TextView;

public class GuessPictureActivityTest extends ActivityInstrumentationTestCase2<GuessPictureActivity> {
    private GuessPictureActivity activity;
    private ImageView imageView;
    private TextView textView;
    private String guessWhoString;
   
           
    public GuessPictureActivityTest() {
        super("com.ben.android.xmlweb.XmlGetter", GuessPictureActivity.class);
    }
   
    @Override
    protected void setUp() throws Exception {       
        super.setUp();
       
        activity = getActivity();
        imageView = (ImageView)getActivity().findViewById(com.ben.android.xmlweb.R.id.imageView);
        textView = (TextView)getActivity().findViewById(com.ben.android.xmlweb.R.id.textFaceName);
        guessWhoString = activity.getResources().getString(com.ben.android.xmlweb.R.string.textGuessName);
    }
   
    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    @UiThreadTest
    public void testAfterStartAQuestionIsAsked() {
        assertNotNull(imageView);
        assertNotNull(textView);
        assertEquals(guessWhoString,textView.getText());
    }   
   
    public void testOnClickTheNameOfPipIsDisplayed() throws InterruptedException{
        Drawable initialDrawable = imageView.getDrawable();
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                imageView.performClick();
            }
        });
       
        getInstrumentation().waitForIdleSync();               
        String expectedText = "Pip";       
        assertEquals(expectedText,textView.getText());
        assertSame(initialDrawable, imageView.getDrawable());   
    }
   
    public void testOnTwoClicksADifferentImageIsDisplayed() {
        Drawable initialDrawable = imageView.getDrawable();
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                imageView.performClick();
                imageView.performClick();
            }
        });
       
        getInstrumentation().waitForIdleSync();               
        assertEquals(guessWhoString,textView.getText());
        assertNotSame(initialDrawable, imageView.getDrawable());
    }
}

If you like to see more, please drop a comment.