Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't create handler inside thread that has not called Looper.prepare(), while implementing IdlingResource

I’m attempting to write Espresso unit test that depends on a component that makes TCP/IP network connection to an external app in order to pass successfully.

The test failed to due the fact that the TCP/IP network took longer than the allowed by Espresso...

Therefore, we need to have TCP/IP code Class TCPConnectionTask implement IdlingResource:

However, I'm getting, this exception:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.app.Activity.<init>(Activity.java:786)
at com.sample.QuicksetSampleActivity.<init>(QuicksetSampleActivity.java:82)
at com.unitTests.QuicksetSampleActivityTest.<init>(QuicksetSampleActivityTest.java:52)

I enclosed the TCPConnectionTask and called Looper.prepare() & also attempted Looper.prepareMainLooper() , with no success, see below (TCPConnectionTask):

/**
     * Async task to connect to create TCPIPDataComm and connect to external IRB.
     *
     */
    public class TCPConnectionTask extends AsyncTask<String, Void, Void > implements IdlingResource {

        String ip_user = null;
        int port_user;
        private ResourceCallback callback;
        private boolean flag = false;
        protected Void doInBackground(String... args) {
            try {

                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(
                        new Runnable() {
                            @Override
                            public void run() {

                                Looper.prepare();
                                //Looper.prepareMainLooper();

                                flag = true;
                                TCPIPDataComm tcp = new TCPIPDataComm(ip_user, port_user);
                                if(tcp != null){
                                    tcp.open();
                                    _TCPDataComm = tcp;

                                    // we can enable the DataComm interface for simulation in UI app
                                    int resultCode = 0;
                                    try {
                                        resultCode = QuicksetSampleApplication.getSetup().setDataCommInfo(
                                                getAuthKey(), _TCPDataComm.getHostName(),
                                                _TCPDataComm.getPortNumber());

                                    } catch (Exception e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                    finally {
                                        //task completed
                                        flag = false;
                                    }
                                    Log.d(QuicksetSampleActivity.LOGTAG,
                                            "Setting DataComm Result = "
                                                    + resultCode
                                                    + " - "
                                                    + ResultCode
                                                    .getString(resultCode));
                                }

                            }
                        }
                );


            } catch (Exception e) {
                e.printStackTrace();

            }
            return null;
        }
        public void setInfo(String ipValue, int portNumber)
        {
            ip_user = ipValue;
            port_user = portNumber;
        }

        @Override
        public String getName() {
            return this.getClass().getName().toString();
        }

        @Override public boolean isIdleNow() {
            if (flag && callback != null) {
                callback.onTransitionToIdle();
            }
            return flag;
        }

        @Override public void registerIdleTransitionCallback(ResourceCallback callback) {
            this.callback = callback;
        }
    }

Below is the relevant snippet of the unit test class, QuicksetSampleActivityTest:

@RunWith(AndroidJUnit4.class)
public class QuicksetSampleActivityTest  extends ActivityInstrumentationTestCase2<QuicksetSampleActivity> {

    private QuicksetSampleActivity newQuicksetSampleActivity = null;
    private final String ip = "192.168.43.139";
    private final int port = 9999;
    private final int timeOutTime = 1000;

    //This is the idling resource that takes time to complete due to network latency...
    private QuicksetSampleActivity.TCPConnectionTask taskIdlingResource = null;

    //const
    public QuicksetSampleActivityTest() {

        super(QuicksetSampleActivity.class);

        //instantiation of idling resource that is used for TCP connection 
        taskIdlingResource = new QuicksetSampleActivity().new TCPConnectionTask();
    }

    @Before
    public void setUp() throws Exception {
        super.setUp();
        injectInstrumentation(InstrumentationRegistry.getInstrumentation());

        //open activity
        newQuicksetSampleActivity = getActivity();
        // Make sure Espresso does not time out
        IdlingPolicies.setMasterPolicyTimeout(timeOutTime * 10, TimeUnit.MILLISECONDS);
        IdlingPolicies.setIdlingResourceTimeout(timeOutTime * 10, TimeUnit.MILLISECONDS);
        //register idling resource
        Espresso.registerIdlingResources(taskIdlingResource);

    }


    @After
    public void unregisterIntentServiceIdlingResource() {
        //unregister idling resource
        Espresso.unregisterIdlingResources(taskIdlingResource);
    }

    //The EditText GUI with the port & Ip was noe found using espresso, we need to set teh ip & port programmatically
    public void setIpandPortToPcBridge() {
        // Use TCPCommunicatuonTask interface
        taskIdlingResource.setInfo(ip, port);
        taskIdlingResource.execute();
    }


    //after TCP connection is made and/or tested
    @Test
    public void testActionBarMenuItemsIrDevicesAfterTCPConnectionFunctions() {

        //we were not able to find the IP & Port fields so set them programmatically
        setIpandPortToPcBridge();
        //open action bar menu
        Espresso.openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());
        //test IR Devices/Functions menu item
        Espresso.onData(Matchers.allOf(Matchers.instanceOf(MenuItem.class), MatcherUtility.menuItemWithTitle("IR Devices/Functions"))).perform(ViewActions.click());
        //add new device will connect the app
        Espresso.onView(ViewMatchers.withId(R.id.btAdd)).perform(ViewActions.click());

        //DeviceFunctionsActivity is rendered
        Espresso.onView(ViewMatchers.withText("IR Devices")).check(ViewAssertions.matches(ViewMatchers.withText("IR Devices")));
        //find the 3 required buttons for this UI
        //test START learning
        //Espresso.onView(ViewMatchers.withText("Start")).check(ViewAssertions.matches(ViewMatchers.withText("Start")));
        //click
        //test CANCEL learning
        //test TEST Learned IR
        //Espresso.onView(ViewMatchers.withText("Test Learned IR")).check(ViewAssertions.matches(ViewMatchers.withText("Test Learned IR")));
        //click
        //test Delete Learn Code
        // Espresso.onView(ViewMatchers.withText("Delete Learn Code")).check(ViewAssertions.matches(ViewMatchers.withText("Delete Learn Code")));
        //click
        //go back
        //ViewActions.pressBack();

    }
}
}   

How can I resolve this exception, and run the Espresso IdlingResource successfully?

like image 649
cyber101 Avatar asked Dec 15 '22 09:12

cyber101


1 Answers

Try

 getInstrumentation().runOnMainSync(new Runnable() {
        @Override
        public void run() {

         // Your testActionBarMenuItemsIrDevicesAfterTCPConnectionFunctions() test body

        }
    });
like image 67
sh0m1 Avatar answered Apr 30 '23 14:04

sh0m1