We just learned how to create and test simple Parrot projects. The next step
is to reexamine the star catalog handler we’ve been writing, and turn it
into a testable project. There will be some changes in how this code gets its
work done, but don’t expect any new features.
I know - you really want to start adding features and working on cool new
stuff. So do I. My workspace is scattered with half-completed steps that talked
about adding new things and using new Parrot features. They kept breaking,
though. They kept breaking because I wasn’t building from a stable, testable
foundation. Today we’re going to get that step our of the way.
Set up the project
Let’s apply what we learned last time putting together larger projects, and
set up a project named stellar.
The setup.pir file is copied directly from the previous project. I’m not ready
for anything more elaborate.
The behavior will be defined in lib/stellar.pir, which is initially
empty. We will steadily build up all of our functionality in the Stellar library
and eventually add a very simple file to act as the face of Stellar for
Parrot. Right now, we just have an empty lib/stellar.pir.
Reimplementing Features
The basic skeleton is in place. Now we can start adding the features we had
written before.
Extracting Details
It’s important to keep test files organized. One helpful approach is to think of
each test as a story. This story describes a single specific thing we want the
Stellar library to accomplish. All of the stories together provide a description
of everything that users should be able to get from the library.
I like to start with the smallest useful test story I can. For this code, I
think that would be extracting the details about a single entry in the HYG
catalog. The whole catalog isn’t even needed. We could get away with using the
header line and the line containing a star’s details.
Names for test files usually follow a common pattern. They start with a number
and summarize what feature is being tested. What purpose does the number serve?
Well, they are probably executed in the order that Parrot finds them, so that
numbering provides a clue for test order. There are no promises about the order,
though. The system looks at each story individually, and you should too. I like
to think of the numbering as simply presenting the order that I came up with the
stories. It provides a simple history of sorts. First I came up with that test,
and I wrote this test after I was comfortable with the first.
In that spirit, I will name the first test story 01-extract-details.t.
Yes, I know that there is a typo in this test code. The key Proper Name should be
ProperName. We’ll come back to that.
What happens if this test is run while stellar.pir is still empty? It fails,
of course. It might be useful to look at how it fails.
setup told us something we already know: extract_star_details hasn’t been
written yet. This is different from a regular test failure, because Parrot
couldn’t even get to the tests. I’m showing this so that you recognize what’s
going on when you see errors like this in your own library.
Adding extract_star_details is easy enough. Just copy the code from the
earlier step.
Let’s run the test again.
There’s only one assertion, so we already know which one failed. This output is a
little vague for larger test stories, though. Let’s run the test file directly.
Okay, now we can fix the typo.
The test should pass now that the correction has been made.
Don’t worry. I won’t submit you to this for every test run. It’s just important
to know what failure looks like before we can reach success.
What have we accomplished so far? We now have a story in which the user, armed
with a header line and a line describing a star, gets an object that she can
examine and manipulate for her own purposes. If we wanted to be thorough, we
could test every field. I’m not going to do that, though. One thing you want to
avoid when making test stories is predicting the future. It’s easy to get
distracted by testing every possible aspect of a single chunk of code when you
could be working on the next story.
These stories aren’t static. We will come back and add more when some
detail doesn’t work out the way we expect it to.
Our first story is pretty much out of the way. Let’s move on to the next one.
Stringifying Stars
Next up is the string representation of a star. In the original application, we
had the say_star_details sub, which printed the star information as soon as it
had been prepared. Stellar is more of a library, though. This means that we
can’t be completely sure what folks will want to do with the star summary once
they have it. They might want to print it, but they might also want to feed it
to an unmanned orbiter for some reason.
Because we can’t predict with certainty what someone will do with the string
summary of a star, this test story will focus on asking for that string.
It’s not hard to create the code which will make this story true, but it does
involve a little more work than the simple copy and paste for
extract_star_details.
Yes, this is mostly a copy and paste of say_star_details. The new details
change the focus from displaying the details to returning them as a simple
string.
What’s most important is that this test passes when handed Sol. How about some
of those stars that don’t have proper names?
It does indeed work.
I am concerned about the heft of this test code. The concern is that I
had to split the CSV text, extract star details, and summarize the star
manually for each star string. Each of those times is an opportunity for me to
make a mistake. I think I would like to have a subroutine which would take the
header fields and a CSV line of star data, and return the extracted details.
Let’s make a new test story for that.
The code to make this work is simple enough.
I do not know if I have saved much work, but it is easier for me to read the
test story. That is important to me, because debugging and improving the code is
easier if I can easily understand what is happening.
Conclusion
It is time to take a break. The script we wrote a while back is evolving into a
tested library that can be used by others. Now that we have our foundation, we
can start building up. Our next step will involve adding some simple search
behavior to the library, and that is a significant improvement. For the moment,
take a little time to relax.