8
Android Studio 3.0 Beta2 

मैं एक endpoint RxJava2 प्रयोग करने के लिए एक सूची प्राप्त करने का परीक्षण कर रहा हूँ। सामान्य रूप से चलते समय ऐप ठीक काम करता है। हालांकि, जब मैं एस्प्रेसो का उपयोग करके परीक्षण करता हूं तो मुझे एक शून्य सूचक अपवाद मिलता है जब मैं कोशिश करता हूं और subscribeOn(scheduler)। शेड्यूलर के लिए मैं subscribeOn और observeOn दोनों के लिए trampoline() का उपयोग करता हूं जो इंजेक्शन दिए जाते हैं।परीक्षण RxJava2 एस्प्रेसो का उपयोग कर और हो रही एक नल पॉइंटर एक्सेप्शन जब suscribeOn

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'io.reactivex.Observable io.reactivex.Observable.subscribeOn(io.reactivex.Scheduler)' on a null object reference 

एस्प्रेसो का उपयोग कर परीक्षण RxJava2 के लिए कुछ भी मुझे लगता है कि क्या करना चाहिए subscribeOn और observeOn के लिए अलग है नहीं है?

@Singleton 
@Component(modules = { 
     MockNetworkModule.class, 
     MockAndroidModule.class, 
     MockExoPlayerModule.class 
}) 
public interface TestBusbyBakingComponent extends BusbyBakingComponent { 
    TestRecipeListComponent add(MockRecipeListModule mockRecipeListModule); 
} 

यह परीक्षण

public class RecipeListModelImp 
     implements RecipeListModelContract { 

    private RecipesAPI recipesAPI; 
    private RecipeSchedulers recipeSchedulers; 
    private CompositeDisposable compositeDisposable = new CompositeDisposable(); 

    @Inject 
    public RecipeListModelImp(@NonNull RecipesAPI recipesAPI, @NonNull RecipeSchedulers recipeSchedulers) { 
     this.recipesAPI = Preconditions.checkNotNull(recipesAPI); 
     this.recipeSchedulers = Preconditions.checkNotNull(recipeSchedulers); 
    } 

    @Override 
    public void getRecipesFromAPI(final RecipeGetAllListener recipeGetAllListener) { 
     compositeDisposable.add(recipesAPI.getAllRecipes() 
       .subscribeOn(recipeSchedulers.getBackgroundScheduler()) /* NULLPOINTER EXCEPTION HERE */ 
       .observeOn(recipeSchedulers.getUIScheduler()) 
       .subscribeWith(new DisposableObserver<List<Recipe>>() { 
        @Override 
        protected void onStart() {} 

        @Override 
        public void onNext(@io.reactivex.annotations.NonNull List<Recipe> recipeList) { 
         recipeGetAllListener.onRecipeGetAllSuccess(recipeList); 
        } 

        @Override 
        public void onError(Throwable e) { 
         recipeGetAllListener.onRecipeGetAllFailure(e.getMessage()); 
        } 

        @Override 
        public void onComplete() {} 
       })); 
    } 

    @Override 
    public void releaseResources() { 
     if(compositeDisposable != null && !compositeDisposable.isDisposed()) { 
      compositeDisposable.clear(); 
      compositeDisposable.dispose(); 
     } 
    } 
} 

शेड्यूलर के लिए इंटरफ़ेस यहाँ है के तहत और परीक्षण मैं ट्रैम्पोलिन उपयोग कर रहा हूँ जो RecipleAPI

के लिए इंजेक्ट किया जाता है

@Module 
public class MockAndroidModule { 
    @Singleton 
    @Provides 
    Context providesContext() { 
     return Mockito.mock(Context.class); 
    } 

    @Singleton 
    @Provides 
    Resources providesResources() { 
     return Mockito.mock(Resources.class); 
    } 

    @Singleton 
    @Provides 
    SharedPreferences providesSharedPreferences() { 
     return Mockito.mock(SharedPreferences.class); 
    } 

    @Singleton 
    @Provides 
    RecipeSchedulers provideRecipeSchedulers() { 
     return new RecipeSchedulers() { 
      @Override 
      public Scheduler getBackgroundScheduler() { 
       return Schedulers.trampoline(); 
      } 

      @Override 
      public Scheduler getUIScheduler() { 
       return Schedulers.trampoline(); 
      } 
     }; 
    } 
} 

नकली मॉड्यूल के लिए मेरी कक्षा है

@Module 
public class MockNetworkModule { 
    @Singleton 
    @Provides 
    public RecipesAPI providesRecipeAPI() { 
     return Mockito.mock(RecipesAPI.class); 
    } 
} 
@RunWith(MockitoJUnitRunner.class) 
public class RecipeListViewAndroidTest { 
    @Inject RecipesAPI recipesAPI; 

    @Mock RecipeListModelContract.RecipeGetAllListener mockRecipeListener; 

    @Rule 
    public ActivityTestRule<MainActivity> mainActivity = 
      new ActivityTestRule<>(
        MainActivity.class, 
        true, 
        false); 

    @Before 
    public void setup() throws Exception { 
     Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 
     BusbyBakingApplication busbyBakingApplication = 
       (BusbyBakingApplication)instrumentation.getTargetContext().getApplicationContext(); 

     TestBusbyBakingComponent component = (TestBusbyBakingComponent)busbyBakingApplication.createApplicationComponent(); 
     component.add(new MockRecipeListModule()).inject(this); 
    } 

    @Test 
    public void shouldReturnAListOfRecipes() throws Exception { 
     List<Recipe> recipeList = new ArrayList<>(); 
     Recipe recipe = new Recipe(); 
     recipe.setName("Test Brownies"); 
     recipe.setServings(10); 
     recipeList.add(recipe); 

     when(recipesAPI.getAllRecipes()).thenReturn(Observable.just(recipeList)); 
     doNothing().when(mockRecipeListener).onRecipeGetAllSuccess(recipeList); 

     mainActivity.launchActivity(new Intent()); 

     onView(withId(R.id.rvRecipeList)).check(matches(hasDescendant(withText("Test Brownies")))); 
    } 
} 

स्टैक ट्रेस: ​​

at me.androidbox.busbybaking.recipieslist.RecipeListModelImp.getRecipesFromAPI(RecipeListModelImp.java:37) 
at me.androidbox.busbybaking.recipieslist.RecipeListPresenterImp.retrieveAllRecipes(RecipeListPresenterImp.java:32) 
at me.androidbox.busbybaking.recipieslist.RecipeListView.getAllRecipes(RecipeListView.java:99) 
at me.androidbox.busbybaking.recipieslist.RecipeListView.onCreateView(RecipeListView.java:80) 
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2192) 
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299) 
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528) 
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595) 
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:758) 
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2363) 
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2149) 
at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2103) 
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2013) 
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388) 
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:607) 
at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178) 
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1237) 
at android.support.test.runner.MonitoringInstrumentation.callActivityOnStart(MonitoringInstrumentation.java:544) 
at android.app.Activity.performStart(Activity.java:6268) 

किसी भी सुझाव के लिए बहुत धन्यवाद,

210 इस तरह घटकों

public class TestBusbyBakingApplication extends BusbyBakingApplication { 
    private TestBusbyBakingComponent testBusbyBakingComponent; 
    private TestRecipeListComponent testRecipeListComponent; 

    @Override 
    public TestBusbyBakingComponent createApplicationComponent() { 
     testBusbyBakingComponent = createTestBusbyBakingComponent(); 
     testRecipeListComponent = createTestRecipeListComponent(); 

     return testBusbyBakingComponent; 
    } 

    private TestBusbyBakingComponent createTestBusbyBakingComponent() { 
     testBusbyBakingComponent = DaggerTestBusbyBakingComponent.builder() 
       .build(); 

     return testBusbyBakingComponent; 
    } 

    private TestRecipeListComponent createTestRecipeListComponent() { 
     testRecipeListComponent = testBusbyBakingComponent.add(new MockRecipeListModule()); 
     return testRecipeListComponent; 
    } 
} 

बनाई गई हैं और expresso परीक्षण के लिए मैं निम्नलिखित कर रहा हूँ है

+1

क्या आप जो अपवाद प्राप्त कर रहे हैं उसका स्टैक ट्रेस पोस्ट कर सकते हैं? इसके अलावा, MockRecipeSchedulersModule इंजेक्शन कहाँ हो रहा है? मैं केवल मॉक रेसिपीलिस्ट मॉड्यूल इंजेक्शन देख रहा हूं। – jdonmoyer

+0

@jdonmoyer क्षमा करें मैं गलत मॉड्यूल शामिल किया गया। इसे MockAndroidModule कहा जाता है जिसमें प्रदाता शामिल होते हैं जो शेड्यूलर लौटाते हैं (मैंने अपना प्रश्न अपडेट किया है)। जिस तरह से वे इंजेक्शन प्राप्त कर रहे हैं वह कन्स्ट्रक्टर इंजेक्शन का उपयोग कर रहा है। इंजेक्ट करें सार्वजनिक पकाने की विधि ListModelImp (NonNull व्यंजनों II व्यंजनों, गैर नल पकाने की विधि शेड्यूलर नुस्खा शेड्यूलर)। मैं तब तक एक स्टैक ट्रेस प्रदान नहीं कर सकता जब तक कि मैं आज घर नहीं आ जाता। धन्यवाद – ant2009

+1

आप व्यंजनों के परीक्षण कार्यान्वयन कहां प्रदान करते हैं? मैं केवल देख सकता हूं, कि इसे रेसिपीलिस्टविस्ट एंड्रॉइडटेस्ट में इंजेक्शन दिया गया है और 'मॉक' प्रकार का सही है? इसके अलावा मैं नहीं देखता, जहां 'MockAndroidModule' को 'TestBusbyBakingComponent' में जोड़ा गया है। क्या आप इस पर विस्तार से बता सकते हैं? –

उत्तर

6

आपके कोडबेस में कई समस्याएं हैं। लेकिन सबसे पहले और सबसे महत्वपूर्ण निम्नलिखित है: आप किसी भी तरह से नई असली वस्तुओं को तुरंत चालू कर रहे हैं (मॉक्स नहीं) और यही कारण है कि आप एनपीई प्राप्त कर रहे हैं, subscribeOn() के साथ कुछ लेना देना नहीं है।

  1. आपको अपने परीक्षण घटक को अपने उत्पादन घटक से विस्तारित करना चाहिए। वर्तमान में यह नहीं है।

    public interface TestRecipeListComponent extends RecipeListComponent {...} 
    
  2. अपने परीक्षण आवेदन वर्ग में आप कॉलबैक मिश्रण कर रहे हैं, यानी आप createApplicationComponent कॉलबैक भीतर TestRecipeListComponent पैदा कर रहे हैं, लेकिन आपको लगता है कि करने के लिए एक और कॉलबैक है: createRecipeListComponent()

  3. आपको MockRecipeListModule में प्रत्येक चीज़ को बाहर निकालना चाहिए। बस घटक को मजाक करें, कि आपको वास्तव में नकल करने की ज़रूरत है। उदाहरण के लिए, यदि आप RecipeAdapter पर नकल करते हैं, तो आप स्क्रीन पर कुछ भी आकर्षित करने के लिए रीसाइक्लिंग व्यू की अपेक्षा कैसे करते हैं? आपको केवल डेटा स्रोत प्रदाता को नकल करने की आवश्यकता है, जो आपके मामले में RecipeApi है। इसके अलावा कुछ भी मजाक नहीं किया जाना चाहिए, यह यूनिट परीक्षण नहीं है, यह उपकरण परीक्षण है।

  4. RecipeListView#onCreate() के भीतर आप एक नया RecipeListComponent पैदा कर रहे हैं, जबकि आप चाहिए नहीं, आप Application वर्ग से है कि घटक, मिलना चाहिए क्योंकि आप पहले से यह वहाँ बनाया है। यह परीक्षणों पर प्रभाव डालता है: आप वहां से निर्भरताओं को नियंत्रित नहीं कर सकते हैं, क्योंकि RecipeListView केवल उन सभी निर्भरताओं को अनदेखा कर देगा जो आपने परीक्षणों से बदल दिए हैं और एक नया घटक बनाएंगे जो अन्य निर्भरताओं को प्रदान करेगा, इस प्रकार आपके स्टब्स नहीं डेटा लौटाएंगे परीक्षण में स्पष्ट रूप से कोडित किया गया है (वास्तव में उन्हें भी नहीं कहा जाएगा, असली वस्तुएं होंगी)। यह वही है जो आप इस मुद्दे का सामना कर रहे थे।

मैंने यह सब ठीक कर दिया है। मैं उस बिंदु पर आया हूं जहां आपने लिखा दावा नहीं है। आपको इसके साथ जारी रखने में परेशानी होनी चाहिए, क्योंकि यह आपके द्वारा उपयोग किए जा रहे तर्क/वास्तुकला से जुड़ा हुआ है।

मैंने एक पुल अनुरोध here खोला है।

+0

ग्रेट वर्क मानते हैं। मैंने कोड की जांच की है और सबकुछ ठीक काम करता है। मुझे टेस्टबस्बी बेकिंग एप्लिकेशन में कुछ मामूली रिफैक्टरिंग करना पड़ा और मैंने यहां एक पीआर बनाया है: https://github.com/azizbekian/BusbyBaking/pull/1। हालांकि, यह मेरे प्रश्न का उत्तर दिया। बहुत धन्यवाद। – ant2009

संबंधित मुद्दे