/ TDD

Interface Overloading - TDD Against UI

WTF...

... is interface overloading. Or Overriding. I kinda toggle between the terms. Right now I'm favoring Interface Overloading; so that's what the title is.

Interface Overloading

Interface overloading is the process I've found in C# and JAVA and Swift to allow TDD when using Libraries and OS Systems. I figure it'll work in most (if not all) languages with interfaces. Except GoLang; this is kinda how GoLang works.

It's a mechanism I stumbled across while TDDing up an android app.
I wrote this tdd-against-android-widgets post while I first found it. It was part of a long and twisted path... Which I think resulted in an excellent tool.

Simple Definition

Extending a class and implementing an interface of a base class method allowing passing around as an interface.

The driving forces behind this discovery is TDD, Extreme Encapsulation, and Clean Architecture.

Mix-In

The basic idea really comes into a mix-in style that gives functionality as required to classes you don't control.

Where I discovered this, and I'm confident it will have significant impact is the UI. It can be utilized against Library and OS classes as easily, but I haven't encountered any cases yet that scream "WIN" as loudly as UI does.

Example

Let's go for a simple example that was TDD'd. The code link is available at the end of the post.

The base class
public class BaseClass 
{
     public string TheMethod(int intVal, bool boolVal) => $"StringVal {intVal} {boolVal}";
}

A simple example with just one method. TheMethod. It builds a string and returns it.

TheMethod is not a virtual method so it's unable to be mocked.
We need a way to pass this around. Really; this example is overly simplified. A MAJOR reason it works so well for UI, is that those often tie themselves to the UI thread, which makes calling textBox.Text = "example"; in a unit test will throw an exception. In Android, it's due to the OS not actually being there.
For C#, I'm working in UWP; and it's a "Ui Changed on non-ui thread" exception.
I suspect very similar if working in WinForms. In general; the UI is thread restricted which forces what I've seen from some frameworks; the ability to force a specific thread.

Now that we have a method we want to use in a method; we need to create the interface to hook into it.

public interface ITheInterface {
   string TheMethod(int intVal, bool boolVal);
}

Yep; same signature. Not a lot to go over here. It's an interface with the same definition... yeah.

OK; next up!

public class WrapperClass : BaseClass, ITheInterface { }

And here we have our Wrapper class. It's the object we'll use in our UI.
In android it'll look like

<com.quantityandconversion.widget.WrapperClass 
  android:id="@+id/tv_score_value"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />

that can be seen here
and in XAML it'll look like

<userControls:WrapperClass x:Name="TxtTitle" Canvas.Top="1" Canvas.Left="1" HorizontalAlignment="Left" HorizontalContentAlignment="Left"/>

and can be seen here
The base class of these are have been TextBox in actual implementation; and did the Interface Overload for setting text.

Both of the above repo's can be explored to see how I've done used it.

Use this WrapperClass control

Using Android; we'll look at the TopItemsAdapter from my HackerNews Reader experiment project.
We retrieve the object like so in our TopItemsAdapter .ViewHolder

/* package */ static class ViewHolder extends RecyclerView.ViewHolder{
    private QacTextView points;
    private QacTextView comments;
    private QacTextView time;
...
    /* package */ ViewHolder(final View itemView) {
        super(itemView);
...
        points = (QacTextView)itemView.findViewById(R.id.tv_score_value);
        comments = (QacTextView)itemView.findViewById(R.id.tv_comments);
        time = (QacTextView)itemView.findViewById(R.id.tv_posted_time);
    }
}

And we'll use these control in the Item class; which I won't reproduce the entirety of here; just some relevant methods

public class Item {
...
   public void postTimeInto(final SetText item) {
        postTime.postTimeInto(item);
    }

    public void commentCountInto(final SetText item) {
        itemComments.commentCountInto(item);
    }

    public void scoreInto(final SetText item) {
        itemScore.scoreInto(item);
    }
...
}

We can see the use of the SetText interface in these methods.
The way this is used by the `TopItemsAdapter' is by passing the correct control into each method

 @Override
    public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
        final Item story = topItemsActivityMediator.itemAt(position);
...
        story.commentCountInto(viewHolder.comments);
        story.scoreInto(viewHolder.points);
        story.postTimeInto(viewHolder.time);
...
    }

and with this pattern in place; you maintain encapsulation, and can still produce the data to be displayed.

Examples

The available simple examples are available in my InterfaceOverride git repo.

Summary

This isn't a complex way to abstract classes you don't control. It's just a really useful one... at least very useful in the UI... for me. I hope it can help others TDD more of the application. Other tricks may be required for other things; but that's a post for another day.

This was a really quick write up; happy to improve and answer questions about the process.

UPDATE

This is a major component in my Hotel Pattern to maintain Clean Architecture.

Quinn Gil

Quinn Gil

Seattle Code Crafter. Quinn beats the drum of FAST Agile, Extreme Programming and Object Oriented Design through MicroObjects. He blogs for fun and frustration of exploring new concepts.

Read More
Interface Overloading - TDD Against UI
Share this