Test expectation language (was Re: [squeak-dev] The Inbox: CollectionsTests-dtl.209.mcz)

Colin Putney colin at wiresong.com
Sun Jan 5 17:54:52 UTC 2014


On Sun, Jan 5, 2014 at 9:05 AM, Frank Shearar <frank.shearar at gmail.com>wrote:


> Oh, one nit with "factoring the functionality such that testing is
> simple and effective": I find that by writing my tests first, I don't
> need to work hard to make things testable. Or the difficulty in
> writing the test in the first place leads to needing to separate the
> functionalities in the first place.
>

Agreed. TDD is very powerful.

Here's an example from the Environments changes I just finished that may
illustrate what I'm talking about. EnvironmentTest has a bunch of tests
that cover exports. Originally, they all looked something like this:

env export: #Griffle.
env at: #Griffle put: value.
self assert: (env public at: #Griffle) == value.

Hard to get simpler than that, right? If  I export a name, then create a
binding with that name, the binding shows up in the dictionary of public
bindings. Testing Nirvana.

But then Levente points out that the implementation is flawed. I've gotta
make imports eager, which affects the way exports are implemented. And it
turns out that, far from being the essence of the functionality, the
'public' dictionary is an implementation detail, and now it's going away.
All my tests are going to have to change. Ugh.

But I'm in luck! After writing several tests like the one above, I had
realized that the code the manipulates the environment always varies, but
the last line, the assertion, is always the same. So I used Extract Method
to create an assertion method called #assertExports:value:. So when the
time came to rewrite the environment implementation, the tests actually
looked like this:


testExplicitExport
env export: #Griffle.
env at: #Griffle put: value.
self assertExports: #Griffle value: value.
assertExports: aSymbol value: anObject
self assert: (env public at: aSymbol) == anObject.


All I had to do was change the assertion method to work like this:


assertExports: aSymbol value: v2

| other |
other := Environment withName: #other.
other import: env.
self assert: (other bindingOf: aSymbol) value = v2



That really does get to the essence of the functionality: if a name is
exported from one environment, and imported into another one, the binding
will be visible to methods compiled in the other environment. And those
test were really helpful when it came to writing the new functionality.
Hurray for testing!

Now, I used TDD here. In fact, I think I actually had the idea of a
public dictionary when I was sitting there with an empty method pane trying
to figure out what the first export test should be. But I still wrote a
fragile, overly-coupled set of tests on my first attempt. This is what I
meant by "testing is hard." (Of course, I'm also proving your point. If I
hadn't used TDD at all, I could have easily ended up with a big mess that
wasn't testable without stubbing out "Smalltalk globals", disabling
SystemChangeNotifier and subclassing Compiler.)

Here's something else I noticed while writing this:
#assertExports:value:is not slick. In fact, it's downright awkward.
But it's pretty easy to
understand, because it follows the same pattern as #assert:equals:. The
reader gets the gist, and if they need to see the details the
implementation is right there in the test class, not some extension to
Object. Also, it's scoped to this test class, other test classes aren't
burdened with assertion methods that don't make sense for them.

Finally, I think there's something to be said for awkwardness its self.
There's value in the ordinariness of SUnit as Smalltalk code. I was saved
from a bunch of tedious and possibly error-prone test rewriting because of
my ordinary Smalltalk coding habits.  I noticed some duplication, extracted
a method using the RB, and continued on my merry way. If I had been using
some kind of slick assertion language, I'm not sure I'd have done that.

Colin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20140105/70a0cdc9/attachment.htm


More information about the Squeak-dev mailing list