2017-03-29 4 views
1

Ich habe MVP in meiner Anwendung. Präsentator SchnittstelleMockito Android Unit Test

public interface ILoginPresenter<V> extends Presenter<V> { 
    void logUserIn(String email, String password, String deviceToken, String deviceType); 
} 

Realisierung hat RX Einzel

mLoginSubscription = mModel.logUserIn(email, password, deviceToken, deviceType) 
      .compose(RxUtil.setupNetworkSingle()) 
      .subscribe(new Subscriber<User>() { 
       @Override 
       public void onCompleted() { 
        Timber.i("Log in complete"); 
       } 

       @Override 
       public void onError(Throwable e) { 
        Timber.e(e, "Retrofit could not get User."); 

        getView().dismissProgressDialog(); 
       } 

       @Override 
       public void onNext(UserResponseRetrofit response) { 
        Timber.i("Retrofit is attempting to get User"); 
        mSaveModel.saveUser(user); 
        getView().dismissProgressDialog(); 
        getView().goToMenuActivity(); 
       } 
      }); 

Auch habe ich Modul für Dagger

@Module 
public class ModelModule { 
    @Provides 
    @ScreenScope 
    public ILoginModel provideLoginModel(LoginModel p) { 
     return p; 
    } 
} 

My Unit-Test aussehen nächste:

@RunWith(RobolectricTestRunner.class) 
@Config(constants = BuildConfig.class, sdk = 21, manifest = "/src/main/AndroidManifest.xml") 
public class LoginPresenterTest { 

    public static final String SOME_OTHER_TOKEN = "someOtherToken"; 
    private AppComponent mAppComponent; 
    private LoginComponent mLoginComponent; 
    private ILoginView mockView; 
    private ModelModule mockModel; 
    private ILoginPresenter mLoginPresenter; 

    @Before 
    public void setup() { 
     // Creating the mocks 
     mockView = Mockito.mock(ILoginView.class); 
     mockModel = Mockito.mock(ModelModule.class); 

     ILoginModel mock = Mockito.mock(ILoginModel.class); 
     User urr = Mockito.mock(User.class); 
     Mockito.when(mockModel.provideLoginModel(null)).thenReturn(mock); 
     Mockito.when(mock.logUserIn("", "", "", "")).thenReturn(ScalarSynchronousSingle.just(urr)); 

     mAppComponent = DaggerAppComponent.builder() 
       .appModule(new AppModule(RuntimeEnvironment.application)) 
       .build(); 

     mLoginComponent = DaggerLoginComponent.builder() 
       .appComponent(mAppComponent) 
       .modelModule(mockModel) 
       .presenterModule(new PresenterModule()) 
       .build(); 

     mLoginPresenter = mLoginComponent.provideLoginPresenter(); 
     mLoginPresenter.setView(mockView); 
    } 

    @Test 
    public void testLogin() { 
     mLoginPresenter.logUserIn("", "", "", ""); 
     try { 
      java.lang.Thread.sleep(20000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     Mockito.verify(mockView).dismissProgressDialog(); 
    } 

So verwenden Dolch muss ich Erstelle Moderator korrekt. Zu diesem Zweck versuche ich Mockito.when zu verwenden. Erstens sieht aus wie diese Linie nicht funktioniert

Der Zielzweck ist es, meine eigene Modellrealisierung zu verwenden, die Single zurückgeben.

verstehe nicht wirklich, warum mein ModelModule-Schein nicht funktioniert?

+1

Was meinst du mit funktioniert nicht? Meinst du, dass es deine Spott nicht zurückgibt? Sind Sie sicher, dass der Dolch 'provideLoginModel' mit dem Argument' null' aufruft? Wenn dir das Argument egal ist '' Mockito.when (mockModel.provideLoginModel (any())). ThenReturn (mock); ' – cyroxis

+1

Danke' any() '- ist die Antwort für ein paar andere meine Fragen –

+0

Great I aktualisierte meine Antwort, um zukünftigen Lesern zu helfen. – cyroxis

Antwort

0

AKTUALISIERT

Das Problem kann sein, dass Sie null verspotten. In diesem Fall wird mockModelnur Rückkehr mock wenn provideLoginModel mit null

Mockito.when(mockModel.provideLoginModel(null)).thenReturn(mock); 
mockModel.provideLoginModel(null) // returns mock 
mockModel.provideLoginModel(new Foo()) // returns null 

Stattdessen können Sie einen Matcher verwenden wie any() genannt wird:

Mockito.when(mockModel.provideLoginModel(any())).thenReturn(mock); 
mockModel.provideLoginModel(null) // returns mock 
mockModel.provideLoginModel(new Foo()) // also returns null 

auf jedem Anruf zurückzukehren mock.

BIG PICTURE Für Unit-Tests würde ich vorschlagen, Dolch nicht verwenden, stattdessen @Mock verwenden und @InjectMocks Sie müssen nur das Objekt, das Sie in Echt der Rest sein, testen können Mocks sein.

@RunWith(RobolectricTestRunner.class) 
@Config(constants = BuildConfig.class, sdk = 21, manifest = "/src/main/AndroidManifest.xml") 
public class LoginPresenterTest { 

    public static final String SOME_OTHER_TOKEN = "someOtherToken"; 

    @Mock 
    ILoginView mockView; 

    @Mock 
    SomePresenterDependency somePresenterDependency 

    @InjectMocks 
    ILoginPresenter mLoginPresenter; 

    @Before 
    public void setup() { 
     MockitoAnnotations.injectMocks(this); 

     mLoginPresenter.setView(mockView); 
    } 

    @Test 
    public void testLogin() { 
     mLoginPresenter.logUserIn("", "", "", ""); 
     try { 
      java.lang.Thread.sleep(20000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     Mockito.verify(mockView).dismissProgressDialog(); 
    } 
} 

Wenn Sie Integrationstests tun und mehrere reale Objekte brauchen Sie nur ein inneres/anonyme Modul für die Komponente erstellen, die das gewünschte Objekt zurückgibt. (anstatt zu versuchen, die Modulschnittstelle zu verspotten).

+0

Ok, aber der Moderator verwendet Abhängigkeiten. Wie wird Mockito wissen, was hinzuzufügen? –

+0

[@InjectMocks] (https://static.javadoc.io/org.mockito/mockito-core/2.7.19/org/mockito/InjectMocks.html) verwendet den Typ und/oder Namen, um die Konstruktorargumente & anzugeben @ Inject'/'@ Autowire' annotierte Mitglieder. Ändern Sie "SomePresenterDependency" in die Abhängigkeit, die Sie über Dagger bereitstellen. – cyroxis

+0

Meine Frage mehr dazu, warum bereits erstellter Mock nicht so geändert werden konnte Mockito.when (RuntimeEnvironment.application.getString (R.string.check_credentials)). ThenReturn ("bla"); –

1

Was ist mit dem Erstellen eines Testmoduls aus Ihrer Produktion Module?

Sehen Sie, wie sie vorschlagen, Tests über Dolch in official site zu tun.

@Module 
public class ModelModuleTest extends ModelModule { 

    @Override 
    public ILoginModel provideLoginModel(LoginModel p) { 
     ... 
    } 
} 

Sie können gespottete Abhängigkeit zu Ihrem Module übergeben.

+0

Ja, ich habe es getan, aber eigentlich sollte mein Modul den originalen überschreiben, da Dagger LoginModel auf jede Weise erstellen wird. und dann gebe ich stub one –

+1

Was das Problem? – azizbekian