UWP HackerNews - Displaying An Item

UWP HackerNews - Displaying An Item

Since we're now able to TDD up the entire app; showing our wrapped control. Sounds like time to display a story title.

I've re-worked the naming; not behavior; of the VBM pattern. It's now the [Hotel UI Pattern](LINK GOES HERE). Same basic idea; but with a metaphor! Check out the new description of it for a little more detail/reasoning.

A Title

The Items have a title; we're gonna display a title!

After a bit of research and refreshing myself with the code base; HUGELY helped by having tests. I'm looking at the HackerNewsAccessTests and going to add a new test for pulling an Item out. To get the title; we need to get the item from the API.

Here is the test I wrote

        [TestMethod]
        public async Task ShouldReturnSpecifiedItem()
        {
            // Arrange
            FakeResponseHandler fakeResponseHandler = new FakeResponseHandler();
            fakeResponseHandler.AddFakeResponse(new Uri($"{HostUrl}/item/123.json"),
                new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new StringContent(@"{""id"":123, ""title"":""My First Title""}")
                });
            Response<Item> response = await new HackerNewsAccess(fakeResponseHandler).Item();

            Item item = response.Body();
            FakeText fakeSetText = new FakeText();

            // Act
            item.Title(fakeSetText);


            // Assert
            fakeSetText.Text.Should().Be("My First Title");

There's a bit going on here. I expected to have to create a few classes to get this test to pass correctly.
This test resulted in the creation of the Item class. But I can't TDD the item class via the HackerNewsAccessTests... I have to do some ItemTests. Which is exactly what I've done.

While the Title method already existed before the test class; it was TDD'd. Just from a different location. I think I've gone over this before. It seems pretty common. Find a new class; then get to the new class.
I put in a matching test with the same expectation as above.

        [TestMethod]
        public void TitleShouldSetConstructorText()
        {
            // Arrange
            Item item = new Item();
            FakeText fakeText = new FakeText();

            // Act
            item.Title(fakeText);

            // Assert
            fakeText.Text.Should().Be("My First Title");
        }

and now I have 2 failing tests! NOES!

... quite a simple fix. Add the value.

public class Item
    {
        public void Title(ISetText item)
        {
            item.Text = "My First Title";
        }
    }

And back to one failing test, in the HackerNewsAccessTests. That's fine; let's keep going on the Item class for a few.

Let's make sure safe behavior if null get's passed in

        [TestMethod]
        public void TitleShouldDoNoethingIfPassedNull()
        {
            ((Action)(() => new Item().Title(null))).ShouldNotThrow();
        }

This updates the Title method to be

    public class Item
    {
        public void Title(ISetText item)
        {
            if (item == null) { return;}
            item.Text = "My First Title";
        }
    }

Why am I checking for null? Because I can write a test to check for null?
That's a terrible reason.
There's no reason... (Android may get a refactor around this). SURE - null can come in via a test. Anywhere else? Maybe? I don't know. I don't see it; so out it goes.
I'm killing the test and the code until I'm shown it's needed.

Only write what you need.

Seriously; that's it. It's REALLY hard to keep that mindset. I struggle with it all the time. I leave these things in the posts because it's important to see that this isn't a perfect journey. I can't just do it. I have to run into a wall; a lot. That's why I do these; I practice. Simplest possible. That's why I hard code in a value. Do I REALLY know how it'll change? I've been wrong.

I'm refactoring Title into TitleInto. It's what Android has; and I like it better. It's more informative of what's happening. It's also DOING something, so the method name should be an action.

Running all tests now that I've removed the null check; and still just the one failure. Excellent.
The issue is that... the HackerNewsAccess#Item() has the following implementation

        public Task<Response<Item>> Item()
        {
            throw new NotImplementedException();
        }

We need to get an API implemented for the Item call.

Uh Oh

As I'm going through preparing to get the item id value out to provide to the network level... I see an issue I didn't refactor.

 public class ItemId
    {
        [JsonProperty("id")]
        public long Id;

        public ItemId(){}
    }

This is a hold over from before I added the ItemsAdapter. I'll have to get this cleaned up as ... "Ahh, Hellz No" is the only response I have to this.

I'm commenting out the failing test in HackerNewsAccessTests and encapsulating the Id in ItemId. This'll break at least one test (probably many) and give me a VERY specific starting point when I pick up again.

I changed the class to be

public partial class ItemId
    {

        private long _id;
    }

The tests should fail somewhere... and ... no. ... uh oh.

Oh - I had one on ignore. Let's try that. YES!
OK, back to failing!
I had ShouldReturnSpecifiedItem which is shown above set to ignore. This test fails. It doesn't get the right item because I've broken the network call. Mostly. It's a failing test; we'll get it working next time.

time passes
It's a broken test; excellent - I know exactly where to start...
The body of our Response is null. We need to dive in and fix that.

Given that our ItemAdapter still looks like

    internal class ItemAdapter : INetworkAdapter<Item>
    {
        public Item FromRawContent(string rawContent)
        {
            throw new System.NotImplementedException();
        }
    }

Not a wonder it's not working.

But that's not dealing with our ItemId that we basically tore apart. That's in our ItemsAdapterTests. We've started putting together some tests

        [TestMethod]
        public void ShouldCreateItemsCallingToObject()
        {
            // Arrange
            // Act
            Items items = new ItemsAdapter().FromRawContent("[]");

            // Assert
            items.Should().NotBeNull();
        }
        [TestMethod]
        public void ShouldCreateItemsFromData()
        {
            // Arrange
            // Act
            Items items = new ItemsAdapter().FromRawContent("");

            // Assert
            items.Count().Should().Be(0);
        }

Which are both passing. We need to get in a failing test. We can't parse the JSON into the ItemId class anymore. It needs to go into the ItemIdJson.

I'm going through a bit of a dance with the Adapters. One thing Retrofit does REALLY well is the black magic for json->object conversion. I'm not going black magic; each adapter is gonna be smart about what adapters it needs. shrug Not the best but it's what I need for now.
The ItemsAdapter uses the ItemIdAdapter internally. I'm not testing that explicitly because it's implemented in support of another class. Part of a refactor. I also want it as internal. :)

... Terrible reason. PUBLICIFICAITON! ... ... Or... I don't need it. I'll go with not needing it. Also acceptable.

My ideas has 3 classes coming into existence. They didn't. They still might; but not yet. I'm avoiding complication and delaying the pain of changing by holding off on these "probably" required classes.

...
I'm going through and working on getting the HackerNewsAccess#Item method test working.
It's not a very exciting thing. Nothing big is standing out. I'm getting the supporting classes in place; adding the ItemIdAdapter and tests... Long; and BORING...

... A few classes and Adapters later; the HackerNewsAccessTests#ShouldReturnSpecifiedItem is passing!

I added the title for better testing; as well as it being the item I want to be displaying initially.

All the tests pass for getting data from the network layer; so now it's time to get the data to the UI.

UI-ify

I'm starting with the Concierge and loading from the network layer. And cheer is over - Time to head out.
next day
Too bad I didn't have about 20 more minutes. That's all it took me to get the title displaying.

Anyway; we've now got the title going all the way to the UI. Ish. Still only in the testing. But good enough for now!

Show Comments