Mockito + Robolectrie + Rxjava Test MVP Architecture Project __java

Source: Internet
Author: User
Tags gettext
Preface

If you're looking for a better project structure on the Web, you'll see hundreds of blogs explaining the pros and cons of various architectures. Unfortunately, most articles do not mention a very important point: unit Testing
When we choose a project structure, the decisive factor is nothing more than a person's preference or project needs. I don't think the MVP architecture is better than the MVVM architecture, or the MVP architecture is a perfect customer solution. The only reason I decided to use the MVP architecture was the simplicity of it.

MVP The MVP representative Model-view-presenter Model is usually understood as data source, whether from a network or a database, or even a handwritten list object can be considered a data source view can generally use activity , fragment, or a custom view to act as. The main function of the view layer is to display the interface, blocking user interaction events presenter in which they play the role of POJO (plain old Java object). It is responsible for communication between the View layer and the Model layer.

Attention:
When we go to achieve a certain presenter, we must pay attention to the Model layer may appear error information to presenter to do the unified treatment. And try to pull the business logic out of the UI layer and put it into the presenter. The first principle of implementing the MVP Architecture Test Principle is to use junit rather than espresso or other third-party automated test frameworks, followed by separate tests for each layer, This is diametrically opposed to the integration test. Therefore, some dependency injection frameworks need to be understood. I recommend the current Hot dagger framework because we are using junit, so we need a separate framework to test the UI functionality. I recommend this is the current more mature robolectric framework. The use of the Mockito framework is also necessary because it is basically the most popular mock test framework in the Test model layer

Model cannot hold presenter and View layer reference
model in the presenter layer should be as far as possible in the form of a simple interface, especially when we use the three-party framework of the
model layer test should never be dependent on the project architecture , it should be independent
Case:

The model interface is created to provide the user with relevant data (we do not know whether the data is from a network or a database) because Rxjava is used so the return type is observable

Public interface Profileinteractor {
    observable<userprofile> getprofile ();
}

and testing this interface method can be directly used Rxjava provided to our Testsubscriber class, as shown below:

public class Profileinteractortest {
    private static final String USER = "USERNAME";
    Profileinteractor interactor;

    @Before public
    void SetUp () {
        interactor = new Profileinteractorimpl (...);
    }

    @Test public
    void Testgetuserprofile () throws Exception {
        testsubscriber<userprofile> subscriber = Testsubscriber.create ();
        Interactor.getprofile (). Subscribe (subscriber);
        Subscriber.assertnoerrors ();
        Subscriber.assertcompleted ();
        Assertthat (Subscriber.getonnextevents (). Get (0). GetName ()). Isequalto (USER);
    }
test the View layer

The test of the View layer is relatively simple, and the difficulty lies in the configuration of the robolectric. First, let's look at the view interface.

Public interface Profileview {
    void display (UserProfile userprofile);
}

The case we chose was to use an Android custom view to act as the view layer

public class Profileframelayout extends Framelayout implements Profileview {private Profilepresenter presenter;

    @BindView (r.id.text_username) TextView textusername;
        @Inject public void Setpresenter (Profilepresenter presenter) {this.presenter = presenter;
    Presenter.attachview (this);
        Public Collectionframelayout {Super (context);
    Init ();
        Public Collectionframelayout (context, AttributeSet attrs) {Super (context, attrs);
    Init ();
        private void init () {View view = Inflate (GetContext (), r.layout.view_profile, this);
    Butterknife.bind (view);
        } @Override protected void Onattachedtowindow () {Super.onattachedtowindow ();
    Presenter.attachview (this);
        } @Override protected void Ondetachedfromwindow () {Super.ondetachedfromwindow ();
    Presenter.detachview (); @Override public void Display(UserProfile userprofile)
    {Textusername.settext (Userprofile.getname ()); }
}

So here's the question: what part of the View should we test, or which code should write the test code?
The answer is: EVERYTHING. All of them must be tested in place.

1 Test whether the view was successfully created
2 test default value is correct
3 test user interaction is passed to presenter
4 test View Just do what it should (show interface)
@RunWith (Robolectricgradletestrunner.class) @Config (constants = buildconfig.class) public class
    profileframelayouttest {private Profileframelayout profileview;

    @Mock Profilepresenter presenter;
        @Before public void SetUp () throws Exception {mockitoannotations.initmocks (this);
        Profileview = new Profileframelayout (runtimeenvironment.application);
    Profileview.setpresenter (presenter);
        @Test public void Testempty () throws Exception {Verify (presenter). Attachview (Profileview);
    Asserthat (ProfileView.textUsername.getText (). toString ()). IsEmpty ();
        @Test public void Testleaveview () throws Exception {Profileview.ondetachedfromwindow ();
    Verify (presenter). Detachview ();
        @Test public void Testreturntoview () throws Exception {reset (presenter);
        Profileview.onattachedtowindow ();
    Verify (presenter). Attachview (Profileview); @Test public void TestDisplay () throws Exception {userprofile user = new UserProfile (user);
        Profileview.display (user);
    Asserthat (ProfileView.textUsername.getText (). toString ()). Isequalto (USER); }
}
Explanation:The top note is to declare a profileframelayout global reference to the Robolectrie configuration, mainly to test it using Mockito to create a mock presenter, because we just want to verify the View through it Whether the layer will successfully invoke the relevant code to the presenter layer because the creation of view in the Android code must be passed into a context, so we use robolectric to provide our runtimeenviroment as context, and passes it to the Profileframelayout object, passing the presenter object to it Test presenter Layer

The way to test presenter and test model is almost just this time we're mocking the view layer. Presenter will receive a view object and a model layer interface object to display the interface and get the data

public void Profilepresenter {
  private final profileinteractor interactor;
  Private Profileview view;

  Public Profilepresenter (Profileinteractor interactor) {
    this.interactor = interactor.
  }

  public void Attachview (Profileview view) {
    This.view = view;
    Fetchanddisplay ();
  }

  public void Dettachview () {
    //not covered by this example:
    //You should handle the subscription
  }

  PU Blic void Fetchanddisplay () {
    //not covered by this example:
    //Your should handle the subscription
    //You should also check if not NULL
    //You should also handle the OnError
    interactor.getuserprofile (). Subscrib E (userprofile-> view.display (userprofile));
  }

For the presenter layer test, our main goal is to ensure the success of the data from the Model layer and successfully passed to the View layer display, we do not care about the correct data.
But if you have a transformation of the data at the presenter level, then you need to verify the correctness of the data.

The code is as follows:

public void Profilepresentertest {
  @Mock
  profileinteractor interactor;
  @Mock
  Profileview view;

  @Before public
  void SetUp () throws Exception {
    mockitoannotations.initmocks (this);
    When (Interactor.getuserprofile ()). Thenreturn (Observable.just (New UserProfile ()));
    Presenter = new Profilepresenter (interactor);
    Presenter.attachview (view);
  }

  @Test public
  void testdisplaycalled () {
    Verify (interactor). GetUserProfile ();
    Verify (View). Display (any ());
  }
SummaryCreate a mockable Model, and if not, then abstract and then encapsulate the use of a Dependency injection framework (dagger) to automatically inject presenter objects into the view layer without manually creating presenter objects in view instead of focusing only on the test output data, Also focus on the interaction between objects if presenter is dependent on the declaration cycle of the View, then we must test it. Test visual changes from your View, not only the text, but also ity or Background color if you change it. Test the view layer to the extreme, not just the text test, but also the background color, visibility and so on to test Test presenter different responses to the model layer when providing different data

Reference Link: https://medium.com/@Miqubel/testing-android-mvp-aa0de6e165e4

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.