This makes the assumption that there is, most of the time, a single,
unique, object that the test is clearly about.
I hasten to admit that my unit testing practice needs a lot to be desired.
But it has not been my experience that there *is* any such object much
of the time.
For example, to test a method, I will sometimes create two equal
objects, manipulate one of them in the
old trusted way, manipulate the other in the new way, and then see if
the objects are equal again.
Which then is *the* subject?
The answer is neither, because what the test is *about* is not an
object, but a method.
Or again, I open a stream to a new file, create a complex object,
persist it on the stream, close
the stream, open another stream reading from the file, reconstitute an
object from it, and then
check that the two objects are isomorphic.  Which is *the* subject?
Neither, because what I am testing is the encoding and decoding
methods, not the objects.

The key paragraph is this one:
<quote>
One could argue that there is not always a single object under test.
In some situations that is correct, for instance when testing the
interaction between objects. But in my experience, most unit tests
have a single object under test.
</quote>

And it is *this* that we really need a blog post on.  I am very ready
to believe that you are a much better tester than I am.
(That wouldn't be hard.)  But *something* interesting is going on when
I think in terms of testing classes and methods to
the point where I find the idea of testing a particular object almost
incomprehensible, yet you think this is the norm.
I take some comfort from the fact that the Gherkin language in
Cucumber (and why oh which has nobody bothered to
write down a proper grammar, let alone even an informal semantics, for
it?  How am I supposed to know what is and what
is not legal Gherkin?)  goes out of its way to conceal the existence
of subjects, should they exist, from test reviewers, and
calls what a test is about a "feature".

Here are two tests for the Quaternion class:
    testMultiplicationByScalarCommutes
      sampleExactScalars do: [:x |
        sampleExactQuaternions do: [:y |
          self assert: (x*y) = (y*x)]].

    testMultiplicationOfPowersCommutes
      sampleExactQuaternions do: [:x |
        |y z|
        y := x squared.
        z := x cubed.
        self assert: (y*z) = (z*y)].

These two methods test important properties of the #* method.

Here's another one, part of testing the test data..

    testExactScalarsAreExactScalars
      sampleExactScalars do: [:each |
        self assert: each isScalar.
        self assert: each isExact].

This tests the *methods* #isScalar and #isExact, and indirectly the
code that generates the test data.
It's not about any particular object.  Nor is it about *one* method.
It's very hard to write a test case that
tests only one method.  In fact my own rather embarrassing experience
is that when a test case of mine
failed it quite often wasn't the method I thought I was testing that
was wrong.  Returning to the
persistence example, it's not testing #saveOn: (object saveOn:
byteStream) or #restore (byteStream restore).
It's testing that the two methods are properly related.  It would be
wrong to call it #testSaveOn: and it
would be wrong to call it #testRestore.  There's a distinction here:
it *is* possible to write methods to test
#saveOn: by itself, by writing various objects and checking that you
get the right bytes.  But if the external
representation is changed (and I need to change it), the tests for
#saveOn: and #restore as such will have
to be rewritten, while the tests for #saveOn: and #restore *together* will not.

Cucumber offers an insight here, I think.  A scenario in Gherkin is
not a test case for an object.
Nor is it a test case for a method.  It is a test case for a composite
*behaviour* of  a system,
at some contextually appropriate level of detail.

Brian Marick had some lovely stickers.  One of them reads "An example
would be handy about now."

I note that your blog post *did* provide an example of testing Date.
In which none of your test cases used 'subject'.
I entirely agree with you that the three methods have good
intention-revealing names.
What we actually need is some examples where 'subject' pays off.



On Mon, 20 Jan 2025 at 04:04, Koen De Hondt
<k...@all-objects-all-the-time.st> wrote:
>
> Dear Pharo users and developers,
>
> In my series of blog posts on testing, I added a follow-up post about a 
> dedicated name for the object under test in SUnit tests, the “subject".
>
> Happy reading!
>
> Ciao,
> Koen
>

Reply via email to