2012-04-27 18 views
7

Bir Etkinlik içinde oluşturulan bir Niyetin içeriğini test eden Android JUnit test vakasını nasıl oluşturabilirim?Birim, bir Etkinlikten başlatılan/gönderilen bir Niyeti nasıl test edebilir?

Bir EditText penceresi içeren bir Etkinliğim var ve kullanıcı gerekli verileri girmeyi bitirdiğinde, Etkinlik, verileri kaydeden ve uygulama işlemiyle devam eden bir IntentService niyetini başlatır. İşte test etmek istiyorum sınıfı, OnEditorActionListener/PasscodeEditorListener ayrı sınıf olarak oluşturulur edilir:

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; 
    } 
} 

nasıl faaliyeti tarafından oluşturulan iki olası giden Amaçları yolunu kesmek ve içeriklerini doğrulayabilir?

Teşekkür

+0

Simülatör kullanıyor musunuz? Belki bir şeyi özlüyorum ama bu şekilde test edemez misin? – Nick

+0

Hem simülatör hem de el cihazını kullanıyorum, ancak bir fark olması gerektiğini düşünmüyorum. Intents'ı test altında herhangi bir belirli aktiviteye enjekte etmenin bir çok yolunu gördüm, ama çıktıyı izlemenin pek çok yolu yok. ContextWrapper'ı ayarladılar ve aramayı "startService()" ile kestiler. Bu ilk arama için çalışır, ancak sonraki aramalar için değil. Bir etkinlik kapanmadan birden fazla hedefi başlatabilir, hepsini izlemeye/test etmeye ilgi duyuyorum. –

cevap

6

Ben başka bir web sitesi yardımıyla ContextWrapper nasıl kullanılacağını düşündüm.

ContextWrapper'ı kullanın ve tüm amaç işlevlerini geçersiz kılın. Tüm Aktivite testlerimi genelleştirerek, ActivityUnitTestCase sınıfını genişlettim ve çözümü bir bölüm olarak uyguladım. 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(); 
    } 

} 
+0

Bu güzel bir çözüm, maalesef yalnızca ActivityUnitTestCase ile çalışıyor, ancak işlevsel test senaryolarıyla çalışmıyor. –

+0

Evet, katılıyorum. Ayrıca, birkaç Niyetin yakalanmasının da mümkün olmadığını buldum. Örneğin, Etkinliğim bazı Başlangıç ​​koşullarında bir IntentService'e bir Niyet gönderebilir, ardından kullanıcı bir düğmeye bastığında bir başkasını başlatabilir. Hepsini yakalamak mümkün değil. –

1

Alternatif olarak, yeniden faktör olabilir kodunuzu "temiz" birim testi (Testten altında sınıfının dışında, alay şeyi olan bir birim testi ortalama) yapmak için. Aslında, benim bir testim var, java.lang.RuntimeException: Stub! aldığımda, ünite test etmek istediğim kod, enjekte ettiğim alayları içeren yeni Intens'ler yaratıyor.

Kendi fabrikalarımı amaç için oluşturmayı düşünüyorum.

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. 
     .... 
    } 
} 

Benim durumum sizinkiyle aynı değil, ama aynı zamanda bunu çözmek için bir fabrika deseni geçerli olabilir inanıyoruz: Sonra benim sınıf-under-testine bir göz alay fabrika enjekte edebilir. Doğru birim testlerini desteklemek için kod yazmayı tercih ederim, ancak çözümünüzün oldukça akıllı olduğunu kabul etmeliyim.