How can I execute a unit test intent launched / sent from an Activity?

How can I create an Android JUnit test case that validates the contents of the Intent generated as part of an Activity?

I have an Activity that contains an EditText window, and when the user has finished entering the necessary data, Activity launches an Intent for the IntentService, which records the data and continues the application process. Here is the class I want to test, created as a separate class: OnEditorActionListener / PasscodeEditorListener:

public class PasscodeActivity extends BaseActivity { EditText m_textEntry = null; PasscodeEditorListener m_passcodeEditorListener = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.passcode_activity); m_passcodeEditorListener = new PasscodeEditorListener(); m_textEntry = (EditText) findViewById(R.id.passcode_activity_edit_text); m_textEntry.setTag(this); m_textEntry.setOnEditorActionListener(m_passcodeEditorListener); } @Override protected void onPause() { super.onPause(); /* * If we're covered for any reason during the passcode entry, * exit the activity AND the application... */ Intent finishApp = new Intent(this, CoreService.class); finishApp.setAction(AppConstants.INTENT_ACTION_ACTIVITY_REQUESTS_SERVICE_STOP); startService(finishApp); finish(); } } class PasscodeEditorListener implements OnEditorActionListener{ @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { PasscodeActivity activity = (PasscodeActivity) v.getTag(); boolean imeSaysGo = ((actionId & EditorInfo.IME_ACTION_DONE)!=0)?true:false; boolean keycodeSaysGo = ((null != event) && (KeyEvent.ACTION_DOWN == event.getAction()) && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER))?true:false; if (imeSaysGo || keycodeSaysGo){ CharSequence seq = v.getText(); Intent guidEntry = new Intent(activity, CoreService.class); guidEntry.setAction(AppConstants.INTENT_ACTION_PASSCODE_INPUT); guidEntry.putExtra(AppConstants.EXTRA_KEY_GUID, seq.toString()); activity.startService(guidEntry); return true; } return false; } } 

How can I intercept two possible outgoing intentions generated by activity and check their contents?

thanks

+7
source share
2 answers

I figured out how to use ContextWrapper using another website.

Use ContextWrapper and override all intent functions. Summarizing all my activity tests, I extended the ActivityUnitTestCase class and implemented this solution as a pad. Enjoy:

 import android.app.Activity; import android.app.Instrumentation; import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.test.ActivityUnitTestCase; public class IntentCatchingActivityUnitTestCase<T extends Activity> extends ActivityUnitTestCase<T> { protected Activity m_activity; protected Instrumentation m_inst; protected Intent[] m_caughtIntents; protected IntentCatchingContext m_contextWrapper; protected class IntentCatchingContext extends ContextWrapper { public IntentCatchingContext(Context base) { super(base); } @Override public ComponentName startService(Intent service) { m_caughtIntents = new Intent[] { service }; return service.getComponent(); } @Override public void startActivities(Intent[] intents) { m_caughtIntents = intents; super.startActivities(intents); } @Override public void startActivity(Intent intent) { m_caughtIntents = new Intent[] { intent }; super.startActivity(intent); } @Override public boolean stopService(Intent intent) { m_caughtIntents = new Intent[] { intent }; return super.stopService(intent); } } // --// public IntentCatchingActivityUnitTestCase(Class<T> activityClass) { super(activityClass); } protected void setUp() throws Exception { super.setUp(); m_contextWrapper = new IntentCatchingContext(getInstrumentation().getTargetContext()); setActivityContext(m_contextWrapper); startActivity(new Intent(), null, null); m_inst = getInstrumentation(); m_activity = getActivity(); } protected void tearDown() throws Exception { super.tearDown(); } } 
+6
source

Alternatively, you can refactor your code to run a β€œclean” unit test (I mean unit test, which has everything mocked except for the class being tested). Actually, I have a situation myself, where I get java.lang.RuntimeException: Stub! , because the code I want for unit test creates new Intents containing the mocks that I entered.

I consider creating my own factory for intentions. Then I could introduce the mocked factory into my test class:

 public class MyClassToBeTested { public MyClassToBeTested(IntentFactory intentFactory) { //assign intentFactory to field } .... public void myMethodToTestUsingIntents() { Intent i = intentFactory.create(); i.setAction(AppConstants.INTENT_ACTION_PASSCODE_INPUT); //when doing unit test, inject a mocked version of the //IntentFactory and do the necessary verification afterwards. .... } } 

My situation is not the same as yours, but I believe that you can apply the factory pattern to solve this problem. I prefer to write code to support true unit tests, but I must admit that your solution is pretty smart.

+1
source

All Articles