Theo
Theo

Reputation: 3139

Testing Views of a Fragment with Robolectric 3.0

In my app,I have a login and a register fragment. I want to test their views ie if the edit texts have hints,and their buttons. I will put here by login fragment which contains two editi texts and one button. There is also a webservice,but I will test it at a later point.

public class LoginFragment extends Fragment {

Button loginButton;
EditText etName,etPass;
String login_name;
String login_pass;
private SessionManager session;
TextView forgotPassBtn;

public LoginFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment

    View v = inflater.inflate(R.layout.fragment_login, container, false);
    Toolbar myToolbar = (Toolbar) v.findViewById(R.id.toolbar);
    ((AppCompatActivity)getActivity()).setSupportActionBar(myToolbar);
    setHasOptionsMenu(true);
    etName = (EditText)v.findViewById(R.id.user_name);
    etPass = (EditText)v.findViewById(R.id.user_pass);
    loginButton = (Button) v.findViewById(R.id.loginButton);

    login_name = etName.getText().toString();
    login_pass = etName.getText().toString();

    forgotPassBtn = (TextView) v.findViewById(R.id.forgotPass);

    session = new SessionManager(getActivity());

    if (session.isLoggedIn()) {
        // User is already logged in. Take him to main activity
        Intent intent = new Intent(getActivity(), Welcome.class);
        startActivity(intent);
        getActivity().finish();
    }
    loginButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            login_name = etName.getText().toString();
            login_pass = etPass.getText().toString();

            SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
            SharedPreferences.Editor editor = settings.edit();

            if(login_name.isEmpty() && login_pass.isEmpty()) {
                Toast.makeText(getActivity(),"Username η κωδικός είναι κενό",Toast.LENGTH_SHORT).show();
            }else {
                editor.putString("id", "");
                editor.putString("user_name", login_name);
                editor.putString("user_pass", login_pass);
                editor.commit();

                loginUser(login_name, login_pass);
            }
        }
    });
   return v;

}



private void loginUser(final String userName,
                       final String password) {
    /*
    Tag used to cancel the request
    HttpsTrustManager.sssMethod();
    */
    String tag_string_req = "req_register";


    StringRequest strReq = new StringRequest(Request.Method.POST,
            Config.URL_LOGIN, new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {
            Log.d("Response", "Register Response: " + response.toString());

            try {
                JSONObject jsonObject = new JSONObject(response);
                if (jsonObject.getString("result").equals("success")) {
                    session.setLogin(true);
                    Toast.makeText(getActivity(), jsonObject.getString("message"), Toast.LENGTH_LONG).show();
                    Intent intent = new Intent(getActivity(),
                            Welcome.class);
                    startActivity(intent);
                    getActivity().finish();
                }

                else if (jsonObject.getString("result").equals("fail")) {

                    Toast.makeText(getActivity(),jsonObject.getString("message"), Toast.LENGTH_LONG).show();

                }

            }catch(JSONException e){
                e.printStackTrace();
            }
            // Launch login activity


            //Toast.makeText(getApplicationContext(), "User successfully registered. Try login now!", Toast.LENGTH_LONG).show();

        }


    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e("Error", "Registration Error: " + error.getMessage());
            Toast.makeText(getActivity(),
                    error.getMessage(), Toast.LENGTH_LONG).show();

        }
    }) {

        @Override
        protected Map<String, String> getParams() {
            // Posting params to register url
            Map<String, String> params = new HashMap<String, String>();
            //params.put("id","");
            params.put("user_name", userName);
            params.put("user_pass", password);

            return params;
        }

    };

    // Adding request to request queue
    AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}

}

Now I am doing some testing with Robolectric.

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class,sdk = 21)
public class LoginFragmentTest {
MainActivity activity;
Button loginButton;

@Before
public void setUp() throws Exception {
    activity = Robolectric.setupActivity(MainActivity.class);
    loginButton = getButton(activity,R.id.registerBtn);
}

@Test
public void loginFragmentShouldNotBeNull(){
    LoginFragment loginFragment = new LoginFragment();
    startFragment(loginFragment, AppCompatActivity.class);
    assertNotNull(loginFragment);

}


@Test
public void shouldHaveUserNameEntry() throws Exception{
    EditText nameEntry = getEditText(activity,R.id.user_name);
    assertViewIsVisible(nameEntry);
    assertThat(nameEntry.getHint().toString(),equalTo(ResourceLocator.getString(R.string.login_username)));
}

}

The getEditText method is defined in another class.

public class ViewLocator {
public static TextView getTextView(Activity activity, int viewId){
    return ((TextView)activity.findViewById(viewId));
}
public static EditText getEditText(Activity activity, int viewId){
    return ((EditText)activity.findViewById(viewId));
}
public static Button getButton(Activity activity, int viewId){
    return ((Button) activity.findViewById(viewId));
}

}

When I run the LoginFragmentTest I get an error on the shouldHaveUserNameEntry() method

java.lang.NullPointerException
at team.football.ael.LoginFragmentTest.shouldHaveUserNameEntry(LoginFragmentTest.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:527)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:265)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:191)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:56)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:157)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Any ideas how to test that edit text view succesfully?

The

        assertViewIsVisible(nameEntry);

passes. The error appears in

        assertThat(nameEntry.getHint().toString(),equalTo(ResourceLocator.getString(R.string.login_username)));

Thanks,

Theo.

Upvotes: 4

Views: 6080

Answers (1)

Steve C
Steve C

Reputation: 1104

Here you add your login fragment on an AppCompactActivity initialized by the startFragment method

@Test
public void loginFragmentShouldNotBeNull() {
 LoginFragment loginFragment = new LoginFragment();
 startFragment(loginFragment, AppCompatActivity.class);
 assertNotNull(loginFragment);   
}

Then you try to find the user_name field on the mainActivity. You added your fragment on an AppCompatActivity and not on your MainActivity (I suppose you add your fragment dynamically in your MainActivity). So the EditText does not exist

@Test
public void shouldHaveUserNameEntry() throws Exception {
EditText nameEntry = getEditText(activity,R.id.user_name);
assertViewIsVisible(nameEntry);
            assertThat(nameEntry.getHint().toString(),equalTo(ResourceLocator.getString(R.string.login_username)));
}

I don't think you need to test your MainActivity. You could use the method startVisibleFragment from SupportFragmentTestUtil which initialize your fragment on an AppCompatActivity

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class,sdk = 21)
public class LoginFragmentTest {

private LoginFragment mLoginFragment = new LoginFragment();

@Before
public void setUp() throws Exception {
    SupportFragmentTestUtil.startVisibleFragment(mLoginFragment);
}

@Test
public void shouldHaveUserNameEntry() throws Exception{
    EditText nameEntry = mLoginFragment.getActivity().findViewById(R.id.user_name);
    assertViewIsVisible(nameEntry);
    assertThat(nameEntry.getHint().toString(),equalTo(RuntimeEnvironment.application.getResources().getString(R.string.login_username)));
}

Upvotes: 5

Related Questions