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