1

I have a Season class. This Season has a few properties: among them, a list of Games. This should be populated from the same source that populated the rest of the Season properties.

I have a test to ensure all items in that list are of type Game.

There is no hard requirement that a Season must contain any Games, so testing that the list is not empty would not be entirely correct -- however, the test Season I'm using has plenty of games in it.

Writing "the minimum amount of code to make a test pass" is already done, because it is the empty list (so there are no not-Game objects).

What would be the fundamental TDD way to get the production code to parse+add games to the Season object?

Would the pragmatic way be to test via the size?


An alternative would be to generate the list of Games in my test, and see if Season.games == list_of_games

The problem with that is that there are a crapload of Foreign relations that will be going into those games, making the test code equivilant to the method that I'm testing -- which I don't think is the way it should work.

Or should I build them "by hand" from the test data -- instead of parsing it?

2
  • What kinda of source are you loading them from? May 12, 2013 at 14:35
  • @WinstonEwert This is data returned from a REST API serving XML. I downloaded the Season endpoint locally to use as sample data.
    – Travis
    May 12, 2013 at 17:35

2 Answers 2

4

If I understand correctly, there is a requirement that states "a Season has a list of 0 or more Game objects. This list shall not contain objects of other types".

The easiest way to verify this requirement is via the method to add items to the list. You have a test to verify that it is possible to add Game objects to the list, and you have a second test to verify that adding non-Game objects fails.

(Exception: If you use a statically-type language, like C++, C# or Java, and you use the type system to ensure only Game objects can be added to the list, the second test is effectively performed by the compiler each time you write code to add an item to the list. There is no need then to write the test yourself.)

5
  • That's statically, not strongly typed. May 12, 2013 at 14:31
  • @WinstonEwert: corrected. May 12, 2013 at 14:42
  • Other than at construction time, I do not plan on allowing items to be added to this list. This is for an API Wrapper so I'm mostly doing a 1:1 with some XML to custom objects. But I get where you're going. Maybe I'll add an addGame(x : Game) method, mock it out, and ensure it was called as many times as I expected. Do you think that is "testing" it enough, or am I mocking the piece that I'm testing?
    – Travis
    May 12, 2013 at 17:38
  • @Travis, what would that do that making an assertion on the length wouldn't do? May 12, 2013 at 19:42
  • @Travis: If your method to add an item to the list is the Season constructor, then just test that you can successfully construct a Season from an XML file that describes a single Game object and that if you try the same with an XML file that describes a non-Game object, you either get an empty list or an exception. May 13, 2013 at 8:20
2

Extracting data from XML or JSON always seems a bit difficult to do in a TDD manner. You end up with a lot of code that looks like:

void parseElement(XMLElement element)
{
     name = element.getAttribute("name");
     home_team = teams.lookup( element.getAttribute("home") );
     away_team = teams.lookup( element.getAttribute("away") );
}

I can add assertions to check the name and teams, but it feels rather hard to justify. The code is so simple that attempting to verify that it actually works seems not worthwhile. Sure it makes sense to run the code and make sure it doesn't go up in flames, and it makes sense to check any non-trivial actions. But it is really worthwhile asserting each and every assignment? All you are really doing is redunandtly stating the same thing.

This is what I think you are hitting. Its a lot of work to verify that the deserialization was correct, but it doesn't really seem worthwhile. That's why you're hesitant to create a list of Games to test against. That's a lot of effort for little gain.

My solution is to devise a framework for extracting information, test that, and mostly trust that it works when applied to your objects. I don't know what language you are using, but here is a pythonish version.

class Season(XMLExtractable):
    XML_FIELDS = {
         'name' : AttributeGetter('name', str),
         'games' : ChildNodeGetter('game', Game),
         ...
    }

The XML_FIELDS dict tells me where each attribute should get its data. The objects constructed here have methods to fetch the value. I've tested all those objects, and I can mostly just trust that they work here. Basically, we move all the redundancy into data and operate on that data. We can test our operations on the data, but we'll assume the data is correct.

6
  • I disagree. If you're parsing the xml as you show, it is worthwhile to have tests, especially as the xml and resulting object graph get more complex. Only time I'd not really test is if the implementation used a built in xml serialized.
    – Andy
    May 12, 2013 at 20:25
  • @Andy, what exactly do you verify in this tests? Do your tests not just end up being almost duplicates of the code itself? May 12, 2013 at 21:08
  • The tests verify that object being hydrated from the xml is hydrated. The code does the assignment, the tests verify property values are as expected.
    – Andy
    May 12, 2013 at 21:12
  • @Andy, do you get a bunch of lines like: name = xml.getAttribute("name") which have parallel assertions in the test: assert foo.name == "foobar";? May 12, 2013 at 22:24
  • Yes.. how else can you be sure you parsed correctly? If in your code you put the element name as naem, hopefully you wouldn't repeat the mistake in your test assertion.
    – Andy
    May 12, 2013 at 22:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.