1

I have an Activity for registration.The Activity takes user's profile like email and password and then upload those values to the server.The server will return those values to Activity after success,for Activity to save them to SharedPreferences.
My question is,how to write a test that return a fake response so that the Activity doesn't have to interact with the real server,and check if the values have been saved exactly to the preference?

This is my Activity:

public class RegisterActivity extends AppCompatActivity implements RegisterRestClientUsage.RegisterCallback{
    private RegisterRestClientUsage registerRestClientUsage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        registerRestClientUsage = new RegisterRestClientUsage(this);
        //...
    }
    public void onClick(View view){
        String email = emailEditText.getText().toString();
        String password = passwordEditText.getText().toString();
        registerRestClientUsage.registerToServer(email,password);
    }
    @Override
    public void registerSuccess(String token, String email) {

        //Save those values to SharedPreferences

        finish();
    }

    @Override
    public void registerFail() {
        finish();
    }
}

RegisterClientUsage.class

public class RegisterRestClientUsage {
    private RegisterCallback callback;
    public interface RegisterCallback{
        void registerSuccess(String token,String email);
        void registerFail();
    }

    public RegisterRestClientUsage(RegisterCallback r){
        callback = r;
    }
    public void registerToServer(String email,String password){
            RequestParams params = new RequestParams();
            params.put("email", email);
            params.put("password", password);

            BaseRestClient.post("api/users/sign_up", params, new AsyncHttpResponseHandler() {
                @Override
                public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                    try {
                        JSONObject responseJson = new JSONObject(new String(responseBody));
                        returnToken = responseJson.optString("token");
                        JSONObject userJson = responseJson.optJSONObject("user");
                        returnEmail = userJson.optString("email");
                        callback.registerSuccess(returnToken,returnEmail);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                    callback.registerFail();
                }
            });
    }
}  

BaseRestClient.class

public class BaseRestClient {
    public static final String BASE_URL =  "https://my.api.com/";
    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.post(getAbsoluteUrl(url), params, responseHandler);
    }

}

Since the RegisterRestClientUsage is embedded in RegisterActivity,I can't find a good way to inject my fake server into the Activity.

Stephane Landelle
  • 6,990
  • 2
  • 23
  • 29
Tony Chen
  • 207
  • 2
  • 13
  • Did you check this http://stackoverflow.com/a/5722193/1349601 ? – g90 Dec 11 '15 at 16:34
  • I think that's a little bit different from my case.I need a fake response from server so I will have a fake implementation of RegisterRestClientUsage to do that.But I don't know where to replace that with the real one since I directly call the real one in my Activity – Tony Chen Dec 12 '15 at 02:56

1 Answers1

1

Thanks to @geek90's help,I finally came up with a solution.I just wrap my real api implemetation(RegisterRestClientUsage.class) with another controller(RegisterController.class):

public class RegisterController{

    private RegisterServer serverSide;

    public RegisterController(RegisterServer r){
        serverSide = r;
    }

    public void registerToServer(String email,String password) {
        RequestParams params = new RequestParams();
        params.put("email", email);
        params.put("password", password);
        serverSide.registerToServer(params);
    }
} 

Let RegisterRestClientUsage.classimplements RegisterServerinterface:

public interface RegisterServer{
    void registerToServer(String email,String  pwd);
}

And in the onCreate()method of RegisterActivity,construct the controller with parameter RegisterRestClientUsage

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_register);
    registerController = new RegisterController(new RegisterRestClientUsage(this));
    //...
}

In this case,I can stub my fake implementation of api into the controller for test:

@RunWith(AndroidJUnit4.class)
public class RegisterActivityTest {
    FakeRegisterRestClientUsage fakeRegisterRestClientUsage;
    @Rule
    public ActivityTestRule<RegisterActivity> activityTestRule = new ActivityTestRule<>(RegisterActivity.class);
    @Before
    public void setUp(){
        Activity activity = activityTestRule.getActivity();
        fakeRegisterRestClientUsage = new FakeRegisterRestClientUsage((RegisterRestClientUsage.RegisterCallback) activity);
        registerController = new RegisterController(fakeRegisterRestClientUsage);
    }
    @Test
    public void savePreferenceAfterRegistration(){
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                registerController.registerToServer("FAKE_NAME", "FAKE_BIRTH", "FAKE_EMAIL", "FAKE_GENDER", "FAKE_PWD", file);
            }
        });
        waitForActionsToComplete();

        //Assert that the data has been properly save to the preferences
    }
    public void waitForActionsToComplete(){
        CountDownLatch signal = fakeRegisterRestClientUsage.signal;
        try {
            signal.await(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Tony Chen
  • 207
  • 2
  • 13
  • Happy to help :) If this works for you please consider marking the answer as accepted so that it does not show up in unanswered questions. – g90 Dec 14 '15 at 16:52