Android HackerNews - Interactive Item

Android HackerNews - Interactive Item

We're at the point we need to do something with the Story we're displaying. Or the job. Either one.

My thoughts on this is to have two actions. A tap and a swipe. The swipe is going to require a change in the list itself (I think). A tap is pretty easy, we'll do that first.

Part of this task is going to be to build a new wrapper for an OS component. The one I'll focus on here is the Toast. I suspect I'll wrap it just like I've wrapped the AlertDialog. Though this time I'll have to TDD it into existence, so it won't QUITE be as extensive from the start, if anytime soon.
:) Such is the cost of other's not TDDing thier code. FOR SHAME! :-P

My expectation here is to use toasts to indicate that, yes, the tap is working. Then figure out how to refactor to a swipe.

It feels like a super silly small step. I know that it's not. But to not just slap something "so simple" into place and try it a few times... It's still fighting 15 years of habit.

Unfortunately; I have this idea of what I'm aiming to do... and I just don't feel it right now.

I need a windows laptop that doesn't suck so I can work on the UWP app. That's currently hooked my thoughts and desires. So...

Until I'm thinking android...

time passes

And down time at the gymnastics studio has gotten a smidge of android written!

The big this is getting a toast to show up when an item is tapped.
It uses the title and puts up a toast.

The Toast isn't wrapped. And technically... I could get away with how it is... but that creates a few lines of uncovered code.
I need to get a test in place that actually calls and verifies the behavior in the onClickListener.

This will come soon; probably with longer nights at the gymnastics studio. I want to get a wrapper around the Toast to be able to unit test it. This seems like a great place to be able to start that!

...

There's a test in here that needs massive refactoring...

time passes

And I wish I'd made mention of what test required refactoring... Oh Well... I'm sure I'll find it again...

Toast has some difficulties being wrapped. The use of static methods to instantiate makes wrapping that behavior... mostly not doable. Not "impossible", but I'm avoiding tools like PowerMock to rewrite test code for test.
My current plan is to just bounce out if it's in a test environment. I expect some grief over this plan; "Test code in production code?!?!?" ... I also probably mention this every time I'm making on of these posts. Having hooks into production just to support testing, I agree is bad; but I'm more opposed to tramp data.

I'm noticing the construction of my wrapper is heavily slanted towards how I use a toast; which; honestly - Yes. I'm not looking to build a perfect wrapper class.... heh... WELL... not perfect but that's for a later challenge.
Right now, I'm looking to be able to TDD code that will use a toast. This wrapper can, and if you're doing it for your own code - should, only involve the functionality you need. There's no reason to build a general purpose wrapper; it'll make it more complex than it needs to be. Evolve it as your needs evolve. ... Think about that while I go delete the Toast API I just put into my Toaster class.

OH... That test... Yes. That needs refactoring. For future me; it's the onBindViewHolderShouldSet* tests. They're kinda big... and repetitive.

Now I'm going to, more or less, C&P the giant test that needs massive refactoring to be able to test that my Toaster class works as a wrapper around the toast.

Here's what I currently have as a wrapper for the toast

public class Toaster {

    private static Toast replacementToast;
    private Toast currentToast;

    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
    /* package */ static void setReplacementToast(final Toast toast){
        replacementToast = toast;
    }

    public Toaster makeToast(final Context context, final CharSequence text, final int duration) {
        currentToast = replacementToast == null ? new Toast(context) : replacementToast;
        
        currentToast.setText(text);
        currentToast.setDuration(duration);

        return this;
    }

    public void show() {
        currentToast.show();
    }
}

It's very small as I'm only implementing what I need.

The tests that drove this are equally compact

public class ToasterTests extends QacTestClass {

    @Mock
    Context mockContext;

    @Test
    public void makeToastSetsValues(){
        final Toast mockToast = Mockito.mock(Toast.class);
        Toaster.setReplacementToast(mockToast);
        final Toaster toast = new Toaster();
        toast.makeToast(mockContext, "SomeText", Toast.LENGTH_LONG);
        toast.show();

        Mockito.verify(mockToast).setText("SomeText");
        Mockito.verify(mockToast).setDuration(Toast.LENGTH_LONG);
    }

    @Test
    public void showShows(){

        final Toast mockToast = Mockito.mock(Toast.class);
        Toaster.setReplacementToast(mockToast);
        final Toaster toast = new Toaster();
        toast.makeToast(mockContext, "SomeText", Toast.LENGTH_LONG);
        toast.show();

        Mockito.verify(mockToast).show();
    }
}

The core of the change to the test to validate the Toast functionality is in the previous assert section. This test's "Arrange" is longer.

 topItemsAdapter.onBindViewHolder(viewHolder, position);

        Toast mockToast = Mockito.mock(Toast.class);
        Toaster.setReplacementToast(mockToast);
        assertThat(containerCaptor.getValue()).isNotNull();
        Mockito.when(mockView.getContext()).thenReturn(Mockito.mock(Context.class));

        //Act
        containerCaptor.getValue().onClick(mockView);

        //Assert
        Mockito.verify(mockToast).show();

Summary

I'm going to end this one here. I've gotten some interactivity in place; and I've created a new OS Dependency Wrapper. Not as full featured, I feel, as the AlertDialog. I may end up rewriting that one to be TDD'd and follow a different pattern. It works for now; and I think it's pretty nice; but I also think it's trying to be a bit too dynamic. I could drop the generic aspect, I think.

Anyway - A tiny bit more functionality; but a whole new useful tool decoupling code from the underlying OS - That should come in useful later.

The Code

Show Comments