7

I have a basic implementation of the Android InputMethodService which I am trying to write unit tests for. My application does not have any Activites, just the implementation of InputMethodService.

So far I have a basic implementation of a ServiceTestCase which is working great:

SoftKeyboardTest.java

    public class SoftKeyboardTest extends ServiceTestCase<SoftKeyboard> {

        @Override
        protected void setUp() throws Exception {
            super.setUp();
            bindService(new Intent(this.getContext(), SoftKeyboard.class));
        }

        public void testShowKeyboard() {
            this.getService().ShowKeyboard();
            assertTrue(this.getService().GetKeyboardIsVisible());
        }

        public void testInsertText() {
            String text = "Hello, world";
            this.getService().InsertText(text);
            assertEquals(this.getService().ReadText(text.length()), text);
        }
}

However, I would like to test some of the functionality which inserts text into the currently focused EditText using getCurrentInputConnection():

SoftKeyboard.java

public void InsertText(String sentence) {
    getCurrentInputConnection().commitText(sentence, 1);
}

public void ReadText(int chars) {
    getCurrentInputConnection().getTextBeforeCursor(chars, 0);
}

Obviously in this case I get a NullPointerException due to there not actually being any focused EditText.

How can I get my test application to launch my service, somehow focus on an EditText, then launch my test cases so that I can properly test my service methods?

CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
  • maybe as they suggest in this thread? (with requestFocus()) http://stackoverflow.com/questions/8080579/android-textfield-set-focus-soft-input-programmatically – Robert Jul 02 '13 at 09:39
  • I would, but I don't have an EditText available. My app is simply a service with no front-end UI. What I'm looking for is requestFocus() on a global control somewhere - perhaps via UI automation? – CodingIntrigue Jul 02 '13 at 09:54
  • Ok, so I googled a bit while looking for android testUtil classes, and I found a project on GitHub but they use some custom imports and I am not sure how well it suits your project. But here it is: https://github.com/japgolly/android-test-utils/tree/master/src/main/java/com/github/japgolly/android/test/fest – Robert Jul 02 '13 at 10:11

1 Answers1

2

If you're doing unit testing on the input method, I'd test it at a level low enough it doesn't need to have an InputConnection. If you're doing integration/acceptance level testing, I'd just write an app with an edit text field, and drive input/output through there.

But really, having done this for 2 years- tests at that level will be almost useless. Your problems won't be from the default edit text implementation- it will be from the thousands of apps that subclass EditText or create their own EditText classes that behave subtly different. You can't automated test for that, and you'll spend man years fixing the bugs on them.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • Having been researching this for the past week, I've come to the same conclusion. I ended up using EasyMock for Android to stub out the two calls to commitText() and getTextBeforeCursor(), was very simple and only took a few lines of code. Thanks for the explanation and good example of why mocking is required in this instance. – CodingIntrigue Jul 03 '13 at 07:20
  • Good luck on the keyboard. You doing anything new and interesting, or is this just a personal project to see what its like? – Gabe Sechan Jul 03 '13 at 10:48
  • Hopefully interesting, trying to build a prototype of a keyboard which provides a large suggestions area combined with gestures from the keyboard. Interesting if it works :) – CodingIntrigue Jul 03 '13 at 11:23
  • Suggestion areas are a tricky thing to get right, especially on smaller devices. Not codewise, but UI-wise. The main issue is space- small devices are starved for vertical space. Although some keyboards get around that by turning the entire keyboard area into a suggestion area with a gesture. We considered that at Swype at one point, but never had time to get to it- it was the mythical phase 2 of our word choice list redesign I did. I do think there's a lot of room for gesture improvements, your problem there is discoverability and user education. – Gabe Sechan Jul 03 '13 at 11:29
  • Completely agree, my suggestion area works really well on tablets but not so much on phones. I've written a custom view which sits outside of Android's default Suggestion/InputView mechanism so I can load in two different methods depending on the size of the device - I just need to figure out the usability problem for smaller devices. – CodingIntrigue Jul 03 '13 at 11:34
  • Yeah, having used the CandidatesView thing built into InputMethodService before, my suggestion would be to avoid it. Its a trivial amount of code to reimplement, and it just reduces your flexibility so badly. It also forces application resizes when showing/hiding. Alternatively, you can consider making your keyboard tablet only. As nice as it is to have a API that spans the two sizes, sometimes size does matter. I'm currently working on a new keyboard that targets only tablets- the features we want don't make sense on anything smaller. – Gabe Sechan Jul 03 '13 at 11:39