2016-12-14 2 views
2

Ich versuche, Instrumentierung Test für meine NetworkMonitorService zu schreiben, wie in der offiziellen „testing your service“ Dokumentation beschrieben.Android: get Verweis auf gestartet Dienst in der Instrumentierung Test

Derzeit Ich bin fest, weil ich nicht herausfinden kann, wie kann ich einen Verweis auf den gestarteten Dienst, um greifen Mocks in sie zu injizieren und Verhalten geltend machen.

Mein Code:

@RunWith(AndroidJUnit4.class) 
@SmallTest 
public class NetworkMonitorServiceTest { 

    @Rule public final ServiceTestRule mServiceTestRule = new ServiceTestRule(); 

    @Test 
    public void serviceStarted_someEventHappenedInOnStartCommand() { 
     try { 
      mServiceTestRule.startService(new Intent(
        InstrumentationRegistry.getTargetContext(), 
        NetworkMonitorService.class)); 
     } catch (TimeoutException e) { 
      throw new RuntimeException("timed out"); 
     } 

     // I need a reference to the started service in order to assert that some event happened 
     // in onStartCommand()... 
    } 
} 

Der betreffende Dienst nicht unterstützt verbindlich. Ich denke, wenn ich die Unterstützung für das Binden implementieren und dann im Test verwenden würde, um einen Verweis auf den Dienst zu erhalten, könnte es funktionieren. Ich mag es jedoch nicht, Produktionscode zu schreiben, nur um Testfälle zu unterstützen ...

Also, wie kann ich (Instrumentierungstest) eine Service testen, die Bindung nicht unterstützt?

+0

Ersetzen Sie Ihre Anwendung durch spezielle Version "für Tests". Tun Sie es, indem Sie einen speziellen Instrumentierungs-Test-Runner bereitstellen. Mock deine Abhängigkeiten es diese "App für Tests". Sehen Sie für Details http://Stackoverflow.com/a/41393275/2711056 – MyDogTom

+0

@MyDogTom, ich dachte über diesen Ansatz nach, aber ich kann nicht einen einfachen Weg sehen, Service-Abhängigkeiten auf diese Weise zu verspotten. Können Sie ein Beispiel im Code angeben? – Vasiliy

Antwort

1

Ersetzen Sie Ihre Anwendung mit spezieller Version "für Tests". Tun Sie es, indem Sie einen speziellen Instrumentierungs-Test-Runner bereitstellen. Mock deine Abhängigkeiten es diese "App für Tests". Hier See for details

ist ein vereinfachtes Beispiel, wie „App für den Test“ verwendet werden kann. Nehmen wir an, Sie möchten die Netzwerkschicht (z. B. Api) während Tests täuschen.

public class App extends Application { 
    public Api getApi() { 
     return realApi; 
    } 
} 

public class MySerice extends Service { 
    private Api api; 
    @Override public void onCreate() { 
     super.onCreate(); 
     api = ((App) getApplication()).getApi(); 
    } 
} 

public class TestApp extends App { 
    private Api mockApi; 

    @Override public Api getApi() { 
     return mockApi; 
    } 

    public void setMockApi(Api api) { 
     mockApi = api; 
    } 
} 

public class MyTest { 
    @Rule public final ServiceTestRule mServiceTestRule = new ServiceTestRule(); 

    @Before public setUp() { 
     myMockApi = ... // init mock Api 
     ((TestApp)InstrumentationRegistry.getTargetContext()).setMockApi(myMockApi); 
    } 

    @Test public test() { 
     //start service 
     //use mockApi for assertions 
    } 
} 

Im Beispiel Dependency Injection wird über Anwendung der Methode getApi getan. Aber Sie können Dolch oder andere Ansätze auf die gleiche Weise verwenden.

+0

Danke, aber ich habe diesen Ansatz bereits ausprobiert. Das Problem hier ist, dass es nicht erlaubt, Mocks pro Test zu injizieren - Sie spezifizieren Mocks für alle Tests, die ausgeführt werden. Dies mag für kleine Anwendungen gut funktionieren, aber in großen Apps (mein Dagger 2 Objektgraph enthält Hunderte von Objekten in ~ 10 Modulen, die von ~ 5 Komponenten verwendet werden) möchten Sie Mocks pro Test injizieren. Ich konnte keinen einfachen Weg finden, dies mit diesem Ansatz zu tun. Hast du? – Vasiliy

+0

@Vasiliy Ich verwende diesen Ansatz nur für den Integrationstest und mache nur die größten/langsamsten Abhängigkeiten (Back-End, in der App-Ebene). Für Komponententests extrahiere ich Logik in separate pojo (oder fast pojo) -Klasse und schreibe Test für diese Klasse. In Ihrem Fall könnte Ihr Dienst eine Art Helfer verwenden, der die gesamte Logik enthält. Decken Sie diesen Helfer mit einer Reihe von Komponententests ab. Schreiben Sie ein paar Integrationstests, nur um zu sehen, dass alles zusammenarbeitet. Sie müssen zu diesem Zeitpunkt nicht alle Fälle abdecken. – MyDogTom

+0

Ja, genau hier stehe ich jetzt - ich habe Komponententests für "Helfer" und "Manager", aber ich möchte einen Integrationstest für den gesamten Service haben. Ich sehe jedoch keine Möglichkeit, einen Integrationstest zu schreiben, der gut ist, ohne die Abhängigkeiten eines bestimmten Dienstes zu verspotten (zumindest muss ich Androids ConnectivityManager, EventBus, ServerPingManager maskieren). Allerdings möchte ich diese Abhängigkeiten nicht für alle Tests vortäuschen - es gibt Tests, die immer noch nicht gemachte Abhängigkeiten verwenden sollten. Auf jeden Fall danke für die gute Idee. +1 – Vasiliy

Verwandte Themen