Search code examples
androidunit-testingandroid-fragmentslistenerclasscastexception

ClassCastException onAttach() when unit testing Android Fragment


I'm trying to test a Fragment that has in interface that must be implemented by the hosting Activity and gets casted to that specific interface's type through onAttach().

Problem: I'm not sure how to implement the necessary interface methods within an Android Unit Test or if it's even necessary to do so. Surprisingly, I haven't found any posts or forums that address this issue.

Test:

public class FragmentTest {

    private ActivityForUnitTesting fragmentHostActivity;
    private ExampleFragment fragmentToTest;

    @Rule
    public ActivityTestRule activityTestRule = new ActivityTestRule<>(ActivityForUnitTesting.class);

    @Before
    public void setUp() {
        fragmentHostActivity = (ActivityForUnitTesting) activityTestRule.getActivity();
        fragmentManager = fragmentHostActivity.getSupportFragmentManager();
        fragmentToTest = new ExampleFragment();
    }

    @Test
    public void testExample() {
        fragmentManager.beginTransaction()
                .replace(R.id.frame_layout_container, fragmentToTest)
                .commit();
    }

}

Fragment:

public class ExampleFragment extends Fragment {

    private ExampleFragmentListener exampleFragmentListener;

    ...

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            exampleFragmentListener = (ExampleFragmentListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement ExampleFragmentListener");
        }
    }

    ...

}

but when I try running a simple test I get:

java.lang.ClassCastException: com.example.package.ActivityForUnitTesting@1234567 must implement ExampleFragmentListener at com.example.package.ExampleFragment.onAttach(ExampleFragment.java:)

I know that the issue is that my Unit Test ActivityForUnitTesting object does not implement the required interface methods. My question is, how do I safely implement those methods within my Unit Test. I haven't had any luck finding a similar question or a solid example.


Solution

  • I didn't find a solution to this, but I did find a "workaround". Instead of using onAttach(), explicitly set your listener through a public method.

    public class ExampleFragment extends Fragment {
    
        private ExampleFragmentListener exampleFragmentListener;
    
        ...
    
        //@Override
        //public void onAttach(Context context) {
        //    super.onAttach(context);
        //    try {
        //        exampleFragmentListener = (ExampleFragmentListener) context;
        //    } catch (ClassCastException e) {
        //        throw new ClassCastException(context.toString() + " must implement ExampleFragmentListener");
        //    }
        //}
    
        public void setExampleFragmentListener(ExampleFragmentListener exampleFragmentListener) {
            this.exampleFragmentListener = exampleFragmentListener;
        }
    
        ...
    
    }
    

    then, you should already have ExampleFragmentListener implemented in your host Activity. Just call

    setExampleFragmentListener(ActivityOrClassThatImplementsExampleFragmentListener)

    from wherever you perform your Activity setup. As a result, the test shouldn't complain about unimplemented methods.