2017-03-29 2 views
1

내 응용 프로그램에 MVP가 있습니다. 발표자는 인터페이스안드로이드 단위 테스트

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

실현을 가지고 RX 싱글

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

이 또한 내가 대거

에 대한 다음과 같은
@Module 
public class ModelModule { 
    @Provides 
    @ScreenScope 
    public ILoginModel provideLoginModel(LoginModel p) { 
     return p; 
    } 
} 

내 단위 테스트보기 모듈이 있습니다

@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(); 
    } 

그래서 사용을 내가 필요로하는 단검 Presenter를 올바르게 작성하십시오. 이 목적을 위해, 나는 Mockito.when를 사용하려고 노력하고있다. 먼저이 라인이 작동하지 않는 것처럼 보입니다.

Mockito.when(mockModel.provideLoginModel(null)).thenReturn(mock); 

목표는 Single을 반환하는 모델 구현을 사용하는 것입니다.

ModelModule의 모의이 작동하지 않는 이유를 정말로 이해하지 못합니까?

+1

작동하지 않는다는 것은 무엇을 의미합니까? 네가 모의를 돌려주지 않는다는 뜻인가요? 단검이'provideLoginModel'을 인수'null'로 호출하고 있습니까? 만약 당신이 그 논쟁에 신경 쓰지 않는다면,'Mockito.when (mockModel.provideLoginModel (any))). then return (mock);' – cyroxis

+1

'any()'- 다른 몇 가지 내 질문에 대한 대답이다. –

+0

Great I 미래의 독자를 돕기 위해 내 대답을 업데이트했습니다. – cyroxis

답변

0

업데이트]

문제는 당신이 의지 을 조롱하는 것을 할 수있다. 이 경우 mockModelprovideLoginModel이 대신 당신이 그런 any() 같은 정규 표현을 사용할 수 있습니다

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

불려 반환 모의는 :

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

모든 통화에 mock를 반환합니다.

BIG PICTURE 단위 테스트 나는 단검을 사용하지 않는 제안의 경우, 대신 당신은 단지 당신이 진짜 나머지는 모의 객체가 될 수있는 것으로 판정하는 객체가 필요 @InjectMocks@Mock를 사용합니다.

@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(); 
    } 
} 

당신은 통합 테스트를하고 그냥 원하는 객체를 반환 구성 요소에 대한 내부/익명의 모듈을 만들 수있는 여러 실물을 필요로하는 경우. (모듈 인터페이스를 조롱하는 대신).

+0

그래도 발표자는 의존성을 사용합니다. Mockito가 어떻게 추가해야하는지 알 수 있습니까? –

+0

[@InjectMocks] (https://static.javadoc.io/org.mockito/mockito-core/2.7.19/org/mockito/InjectMocks.html)는 유형 및/또는 이름을 사용하여 생성자 인수 & @ Inject' /'@ Autowire' 주석이 달린 멤버들. 'SomePresenterDependency'를 단검을 통해 제공하는 의존성으로 변경하십시오. – cyroxis

+0

내 질문 왜 Mockito.when (RuntimeEnvironment.application.getString (R.string.check_credentials))와 같이 이미 생성 된 mock을 수정할 수 없습니다. thenReturn ("bla"); –

1

프로덕션에서 테스트 모듈을 만드는 방법은 무엇입니까? Module?

대거 in official site을 통해 테스트를 수행하는 방법을 확인하십시오.

@Module 
public class ModelModuleTest extends ModelModule { 

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

Module에 조롱 된 종속성을 전달할 수 있습니다.

+0

그래, 그렇게 했어.하지만 대거가 어떤 식 으로든 LoginModel을 만들 것이기 ​​때문에 실제로 내 모듈이 원래 모듈을 완전히 오버라이드해야합니다. 그런 다음 스텁 하나를 반환합니다. –

+1

무엇이 문제입니까? – azizbekian