On 04/21/2018 08:25 PM, Gregg Williams wrote:
> Hi—I’m a beginner in Pharo 
Hi Gregg, welcome!
> and am working my way through Pharo by Example 5.0 (PbE) and Learning OOP and 
> TDD with Pharo (LOTWP).
>
> I’m currently going through 7.4 Designing a test, in LOTWP, which covers 
> testing whether a string has no repeated characters, adding the method String 
> >> isIsogramSet.
>
> GramCheckerTest, a class for testing, has the following methods:
>
> —
> isograms
>       "list of isograms; used for testing"
>
>       ^ #('pharo' 'pathfinder' 'xavier' 'lumberjacks’)
>
>
> testAllIsogramSet
>       "using each word in list named 'isograms'"
>
>       self isograms do: [ :word | self assert: word isIsogramSet ]
> —
>
> Here are my questions:
>
> 1) These two methods are defined on the instance side (the Class button is 
> *not* selected). If so, what is the receiver when they are used?
The receiver is an instance of the test class, which is most likely a
subclass of TestCase.
>
> 2) In testAllIsogramSet, why do you need ‘self’? After all ‘isograms’ is a 
> data structure, and its message is ‘do:’
"isograms" is not, strictly speaking, the name of a data structure. It's
the name (formally, "selector") of a message. The method for responding
to that message is defined by the source code you list above. That
method answers an object of class Array. So in order to get a reference
to that array in the actual test case method, it has to send the message
#isograms (the # indicates a Symbol -- all message selectors are
Symbols), to self. Since the class of the receiver understands messages
with that selector, it evaluates the method, and the method answers the
reference to the Array.
>
> 3) As an add-on to 2), what does ‘self’ refer to? The class GramCheckerTest? 
> If so, wouldn’t that make testAllIsogramSet a class method? But 
> testAllIsogramSet doesn’t appear in the class browser when I click the Class 
> button when the Class pane shows GramCheckerTest.
When these methods are evaluated, self will be bound to the receiver.
The receiver will be an instance of GramCheckerTest. (or possibly a
subclass of GramCheckerTest, if any subclasses exist -- they would
inherit the method unless overridden.) The test framework creates an
instance of the test class to actually run the test. Let's take a look
at the code involved.

One way to run your test would be to evaluate

  GramCheckerTest run: #testAllIsogramSet.

GramCheckerTest most likely inherits the method for #run: from TestCase,
and you can see it on the class side of TestCase. It looks like this:

run: aSymbol
    "Execute a testcase name, aSymbol, and return a test result."
   
    ^(self selector: aSymbol) run

So it sends the message #selector: to self. Note a potentially confusing
point here -- #selector: is a selector. Kind of like if my name were
"Name." Self here is the class GramCheckerTest. As long as
GramCheckerTest doesn't define its own version of #selector:, it
inherits that method from TestCase (class side, still), and that method
looks like this:

selector: aSymbol
    "Return a test case with aSymbol as selector but does not execute it."
    ^self new setTestSelector: aSymbol

This sends #new to self. Self is, once again, the class GramCheckerTest.
A class responds to the message #new by creating a new instance of
itself. So now you've got an *instance* of GramCheckerTest, and any
messages you send to that will be responded to by methods on the
instance side.

Well, I would not be surprised if this explanation has confused you, but
I hope it's enlightened you a bit as well. Please ask more questions
until you understand what's going on here -- if you understand this you
will be well positioned to understand the entire language.

Regards,
-Martin


Reply via email to