Thus started my personal quest "How is Test Driven Development (TDD) accomplished on Android". All Java-lovers including myself will somehow utter the words Unit Testing and Continuous Integration. True, but how do you manage this on a platform which is mobile and where device emulators, well, frankly s*ck.
I finally ended up with Robolectric.org, a framework that allows you to run your code against your JVM. Yes, your JVM. Anxious as a 6-year-old that just got some presents from Santa, I started coding.
... and got stuck. Where the hell is the documentation? Oh right, Stackoverflow.
Frustrated about the copy-pasting from Stackoverflow, I wanted to share some of the examples I found/used that hopefully will ease-up your life, and help you develop up-spec quality Android applications.
Imaging that you developed an activity that fetches information from the Extras bundle passed in your intent:
public class MyActivity extends Activity {
private final static String TAG = MyActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
Bundle bundle = getIntent().getExtras();
String resource_url = (bundle == null ? "" : bundle.getString("URL", ""));
String resource_name = (bundle == null ? "" : bundle.getString("RESOURCE", ""));
((TextView) this.findViewById(R.id.txt1)).setText(resource_name);
((TextView) this.findViewById(R.id.txt2)).setText(resource_url);
}
}
You would like to know that when you pass the information via the intent, that it will place the corresponding strings in the foreseen TextViews.
package ...
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.shadows.ShadowActivity;
import org.robolectric.util.ActivityController;
import ...
@RunWith(RobolectricGradleTestRunner.class)
public class MyActivityTest {
@Before
public void setUp() {
//whatever you need to have done before a test is run
}
@Test
public void testIfTextFieldsAreFilled() {
Bundle bundle = new Bundle();
bundle.putString("URL", "http://www.google.be");
bundle.putString("RESOURCE", "Google");
Intent intent = new Intent(Robolectric.getShadowApplication().getApplicationContext(), MyActivity.class);
intent.putExtras(bundle);
Activity activity = Robolectric.buildActivity(MyActivity.class).withIntent(intent).create().get();
ShadowActivity testActivity = Robolectric.shadowOf(activity);
Assert.assertEquals("Google", ((TextView) testActivity.findViewById(R.id.txt1)).getText().toString());
Assert.assertEquals("http://www.google.be", ((TextView) testActivity.findViewById(R.id.txt2)).getText().toString());
}
}
There is actually quite an important difference. You would expect that you would test against the "built" Activity, but you need to invoke the ShadowActivity via Robolectric.shadowOf(...);. If you don't, your test code will not pass the intent correctly and your test results will fail.
Activity activity = Robolectric.buildActivity(MyActivity.class).withIntent(intent).create().get();
ShadowActivity testActivity = Robolectric.shadowOf(activity);
Happy testing! Happy Developer! Happy Customer!

Geen opmerkingen:
Een reactie posten