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

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

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

Frank Shearar-3
On 3 January 2014 20:06, Tobias Pape <[hidden email]> wrote:

>
> On 03.01.2014, at 20:44, Frank Shearar <[hidden email]> wrote:
>
>> On 3 January 2014 19:28, Tobias Pape <[hidden email]> wrote:
>>>
>>> On 03.01.2014, at 20:11, Frank Shearar <[hidden email]> wrote:
>>>
>>>> On 2 January 2014 20:55,  <[hidden email]> wrote:
>>>>> David T. Lewis uploaded a new version of CollectionsTests to project The Inbox:
>>>>> http://source.squeak.org/inbox/CollectionsTests-dtl.209.mcz
>>>>>
>>>>> ==================== Summary ====================
>>>>>
>>>>> Name: CollectionsTests-dtl.209
>>>>> Author: dtl
>>>>> Time: 2 January 2014, 3:55:41.062 pm
>>>>> UUID: 5681f129-af93-4f97-9449-b2391be6c8a3
>>>>> Ancestors: CollectionsTests-fbs.208
>>>>>
>>>>> Provide TextAttributesScanningTest to verify text attribute filein and fileout.
>>>>>
>>>>> Five tests are marked as expected failures. These are tests for text attributes that are apparently unused, and that are likely candidates for removal from the image.
>>>>>
>>>>> There is one failure in a test for PluggableTextAttribute, which is a kind of text attribute that is used by SqueakMap. This is probably a legitimate failure that should be fixed.
>>>>>
>>>>> =============== Diff against CollectionsTests-fbs.208 ===============
>>>> <snip>
>>>>> Item was added:
>>>>> + ----- Method: TextAttributesScanningTest>>testTextAttributeClassFor (in category 'testing') -----
>>>>> + testTextAttributeClassFor
>>>>> +       "Verify class identifiers as used in RunArray class>>scanFrom:"
>>>>> +
>>>>> +       self assert: (TextAttribute classFor: $a) equals: TextAlignment.
>>>>> +       self assert: (TextAttribute classFor: $f) equals: TextFontChange.
>>>>> +       self assert: (TextAttribute classFor: $F) equals: TextFontReference.
>>>>> +       self assert: (TextAttribute classFor: $b) equals: TextEmphasis.
>>>>> +       self assert: (TextAttribute classFor: $i) equals: TextEmphasis.
>>>>> +       self assert: (TextAttribute classFor: $u) equals: TextEmphasis.
>>>>> +       self assert: (TextAttribute classFor: $=) equals: TextEmphasis.
>>>>> +       self assert: (TextAttribute classFor: $n) equals: TextEmphasis.
>>>>> +       self assert: (TextAttribute classFor: $-) equals: TextKern.
>>>>> +       self assert: (TextAttribute classFor: $+) equals: TextKern.
>>>>> +       self assert: (TextAttribute classFor: $c) equals: TextColor.
>>>>> +       self assert: (TextAttribute classFor: $L) equals: TextLink.
>>>>> +       self assert: (TextAttribute classFor: $R) equals: TextURL.
>>>>> +       self assert: (TextAttribute classFor: $q) equals: TextSqkPageLink.
>>>>> +       self assert: (TextAttribute classFor: $p) equals: TextSqkProjectLink.
>>>>> +       self assert: (TextAttribute classFor: $P) equals: TextPrintIt.
>>>>> +       self assert: (TextAttribute classFor: $d) equals: TextDoIt.
>>>>
>>>> Yay for #assert:equals:! The expected value goes first, though:
>>>> otherwise you get a message something like "Expected actualValue but
>>>> was expectedValue". The same applies, as far as I can see, to the
>>>> other #assert:equals: calls.
>>>
>>> Which is a  counter-intuitive order for me...
>>> Is that ansi?
>>
>> It's SUnit. I don't particularly like it, but that's the API.
>>
>> What I'd _really_ like is something like Phexample syntax, which would have
>>
>> (TextAttribute classFor: $d) should = TextDoIt.
>>
>> (Very RSpec-ish. Having said that, RSpec's moved away from should
>> syntax because it requires monkey patching. So `foo should == :bar` is
>> now `expect(foo).to eq(:bar)`. Translating that back into Smalltalk
>> would probably look something like `Expect this: (TextAttribute
>> classFor: $d) toEqual: TextDoIt`. Ack!)
>
> and there we are again:
>         `Expect this: (TextAttribute classFor: $d) toEqual: TextDoIt`
> can easily be:
>         self assertThat: (TextAttribute classFor: $d) isEqualTo: TextDoIt
> (which is near self assert: a equals: b, but the other way round again ;)
>
> What about
> a) instvar named `it' and initialised to self or
> b) method named #it that returns self (or what the user wants, like an "asserter")
> and do
>         it should: (TextAttribute classFor: $d) beEqualTo: TextDoIt
> or
>         self it should: (TextAttribute classFor: $d) beEqualTo: TextDoIt

Would it be blasphemy to have a global or class called It? It should:
$a equal: $b.

>>> I like the usage as in the example better..
>>
>> I agree. I just held my nose and adapted. Altering the API means never
>> being sure that you changed everything, and when you get it wrong you
>> make someone's life a misery because their debug error message, meant
>> to _aid_ them, now _lies_ to them.
>
> HmHmmm. But frankly, most people do not look up the argument names and
> just use it intuitively and they then “think” the system is lying (while
> it is not)…

I've burned myself enough times that I just remember that expected goes first.

frank

> Best
>         -Tobias

Reply | Threaded
Open this post in threaded view
|

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

Tobias Pape

On 03.01.2014, at 21:36, Frank Shearar <[hidden email]> wrote:

> On 3 January 2014 20:06, Tobias Pape <[hidden email]> wrote:
>>
>> On 03.01.2014, at 20:44, Frank Shearar <[hidden email]> wrote:
>>
>>> On 3 January 2014 19:28, Tobias Pape <[hidden email]> wrote:
>>>>
>>>> On 03.01.2014, at 20:11, Frank Shearar <[hidden email]> wrote:
>>>>
>>>>> On 2 January 2014 20:55,  <[hidden email]> wrote:
>>>>>> David T. Lewis uploaded a new version of CollectionsTests to project The Inbox:
>>>>>> http://source.squeak.org/inbox/CollectionsTests-dtl.209.mcz
>>>>>>
>>>>>> ==================== Summary ====================
>>>>>>
>>>>>> Name: CollectionsTests-dtl.209
>>>>>> Author: dtl
>>>>>> Time: 2 January 2014, 3:55:41.062 pm
>>>>>> UUID: 5681f129-af93-4f97-9449-b2391be6c8a3
>>>>>> Ancestors: CollectionsTests-fbs.208
>>>>>>
>>>>>> Provide TextAttributesScanningTest to verify text attribute filein and fileout.
>>>>>>
>>>>>> Five tests are marked as expected failures. These are tests for text attributes that are apparently unused, and that are likely candidates for removal from the image.
>>>>>>
>>>>>> There is one failure in a test for PluggableTextAttribute, which is a kind of text attribute that is used by SqueakMap. This is probably a legitimate failure that should be fixed.
>>>>>>
>>>>>> =============== Diff against CollectionsTests-fbs.208 ===============
>>>>> <snip>
>>>>>> Item was added:
>>>>>> + ----- Method: TextAttributesScanningTest>>testTextAttributeClassFor (in category 'testing') -----
>>>>>> + testTextAttributeClassFor
>>>>>> +       "Verify class identifiers as used in RunArray class>>scanFrom:"
>>>>>> +
>>>>>> +       self assert: (TextAttribute classFor: $a) equals: TextAlignment.
>>>>>> +       self assert: (TextAttribute classFor: $f) equals: TextFontChange.
>>>>>> +       self assert: (TextAttribute classFor: $F) equals: TextFontReference.
>>>>>> +       self assert: (TextAttribute classFor: $b) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $i) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $u) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $=) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $n) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $-) equals: TextKern.
>>>>>> +       self assert: (TextAttribute classFor: $+) equals: TextKern.
>>>>>> +       self assert: (TextAttribute classFor: $c) equals: TextColor.
>>>>>> +       self assert: (TextAttribute classFor: $L) equals: TextLink.
>>>>>> +       self assert: (TextAttribute classFor: $R) equals: TextURL.
>>>>>> +       self assert: (TextAttribute classFor: $q) equals: TextSqkPageLink.
>>>>>> +       self assert: (TextAttribute classFor: $p) equals: TextSqkProjectLink.
>>>>>> +       self assert: (TextAttribute classFor: $P) equals: TextPrintIt.
>>>>>> +       self assert: (TextAttribute classFor: $d) equals: TextDoIt.
>>>>>
>>>>> Yay for #assert:equals:! The expected value goes first, though:
>>>>> otherwise you get a message something like "Expected actualValue but
>>>>> was expectedValue". The same applies, as far as I can see, to the
>>>>> other #assert:equals: calls.
>>>>
>>>> Which is a  counter-intuitive order for me...
>>>> Is that ansi?
>>>
>>> It's SUnit. I don't particularly like it, but that's the API.
>>>
>>> What I'd _really_ like is something like Phexample syntax, which would have
>>>
>>> (TextAttribute classFor: $d) should = TextDoIt.
>>>
>>> (Very RSpec-ish. Having said that, RSpec's moved away from should
>>> syntax because it requires monkey patching. So `foo should == :bar` is
>>> now `expect(foo).to eq(:bar)`. Translating that back into Smalltalk
>>> would probably look something like `Expect this: (TextAttribute
>>> classFor: $d) toEqual: TextDoIt`. Ack!)
>>
>> and there we are again:
>>        `Expect this: (TextAttribute classFor: $d) toEqual: TextDoIt`
>> can easily be:
>>        self assertThat: (TextAttribute classFor: $d) isEqualTo: TextDoIt
>> (which is near self assert: a equals: b, but the other way round again ;)
>>
>> What about
>> a) instvar named `it' and initialised to self or
>> b) method named #it that returns self (or what the user wants, like an "asserter")
>> and do
>>        it should: (TextAttribute classFor: $d) beEqualTo: TextDoIt
>> or
>>        self it should: (TextAttribute classFor: $d) beEqualTo: TextDoIt
>
> Would it be blasphemy to have a global or class called It? It should:
> $a equal: $b.
Strangely, I like it.

>
>>>> I like the usage as in the example better..
>>>
>>> I agree. I just held my nose and adapted. Altering the API means never
>>> being sure that you changed everything, and when you get it wrong you
>>> make someone's life a misery because their debug error message, meant
>>> to _aid_ them, now _lies_ to them.
>>
>> HmHmmm. But frankly, most people do not look up the argument names and
>> just use it intuitively and they then “think” the system is lying (while
>> it is not)…
>
> I've burned myself enough times that I just remember that expected goes first.
Yes. But we’ve got about 80 students per year that get taught testing
and do not have this knowledge sucked in, IIRC, half does it this way,
half the other.

We could make a preference *duck-and-cover*

Best
        -Tobias




signature.asc (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

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

Colin Putney-3



On Fri, Jan 3, 2014 at 3:42 PM, Tobias Pape <[hidden email]> wrote:
> Would it be blasphemy to have a global or class called It? It should:
> $a equal: $b.

Strangely, I like it.

Why? "It should a equal b" isn't a coherent sentence. 

SUnit doesn't try to make everything into an executable specification (which is a good thing), but at least "self assert: a equals: b" reads like fluent Smalltalk.

Colin


Reply | Threaded
Open this post in threaded view
|

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

Casey Ransberger-2
In reply to this post by Frank Shearar-3
I tried doing RSpec for Squeak a while back. I don't think it works well. Or I should say: what I tried didn't work well. Your example is pretty close to what I tried:)

I think keeping SUnit as simple as possible in the core system is the best plan. In an external package though, I could see something in the way of an OMeta or PetitParser being applied toward doing spec style tests in Smalltalk.

Of course don't let me stop you! You might come up with a very nice pure-ST DSL for it yet...

> On Jan 3, 2014, at 12:36 PM, Frank Shearar <[hidden email]> wrote:
>
>> On 3 January 2014 20:06, Tobias Pape <[hidden email]> wrote:
>>
>>> On 03.01.2014, at 20:44, Frank Shearar <[hidden email]> wrote:
>>>
>>>> On 3 January 2014 19:28, Tobias Pape <[hidden email]> wrote:
>>>>
>>>>> On 03.01.2014, at 20:11, Frank Shearar <[hidden email]> wrote:
>>>>>
>>>>>> On 2 January 2014 20:55,  <[hidden email]> wrote:
>>>>>> David T. Lewis uploaded a new version of CollectionsTests to project The Inbox:
>>>>>> http://source.squeak.org/inbox/CollectionsTests-dtl.209.mcz
>>>>>>
>>>>>> ==================== Summary ====================
>>>>>>
>>>>>> Name: CollectionsTests-dtl.209
>>>>>> Author: dtl
>>>>>> Time: 2 January 2014, 3:55:41.062 pm
>>>>>> UUID: 5681f129-af93-4f97-9449-b2391be6c8a3
>>>>>> Ancestors: CollectionsTests-fbs.208
>>>>>>
>>>>>> Provide TextAttributesScanningTest to verify text attribute filein and fileout.
>>>>>>
>>>>>> Five tests are marked as expected failures. These are tests for text attributes that are apparently unused, and that are likely candidates for removal from the image.
>>>>>>
>>>>>> There is one failure in a test for PluggableTextAttribute, which is a kind of text attribute that is used by SqueakMap. This is probably a legitimate failure that should be fixed.
>>>>>>
>>>>>> =============== Diff against CollectionsTests-fbs.208 ===============
>>>>> <snip>
>>>>>> Item was added:
>>>>>> + ----- Method: TextAttributesScanningTest>>testTextAttributeClassFor (in category 'testing') -----
>>>>>> + testTextAttributeClassFor
>>>>>> +       "Verify class identifiers as used in RunArray class>>scanFrom:"
>>>>>> +
>>>>>> +       self assert: (TextAttribute classFor: $a) equals: TextAlignment.
>>>>>> +       self assert: (TextAttribute classFor: $f) equals: TextFontChange.
>>>>>> +       self assert: (TextAttribute classFor: $F) equals: TextFontReference.
>>>>>> +       self assert: (TextAttribute classFor: $b) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $i) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $u) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $=) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $n) equals: TextEmphasis.
>>>>>> +       self assert: (TextAttribute classFor: $-) equals: TextKern.
>>>>>> +       self assert: (TextAttribute classFor: $+) equals: TextKern.
>>>>>> +       self assert: (TextAttribute classFor: $c) equals: TextColor.
>>>>>> +       self assert: (TextAttribute classFor: $L) equals: TextLink.
>>>>>> +       self assert: (TextAttribute classFor: $R) equals: TextURL.
>>>>>> +       self assert: (TextAttribute classFor: $q) equals: TextSqkPageLink.
>>>>>> +       self assert: (TextAttribute classFor: $p) equals: TextSqkProjectLink.
>>>>>> +       self assert: (TextAttribute classFor: $P) equals: TextPrintIt.
>>>>>> +       self assert: (TextAttribute classFor: $d) equals: TextDoIt.
>>>>>
>>>>> Yay for #assert:equals:! The expected value goes first, though:
>>>>> otherwise you get a message something like "Expected actualValue but
>>>>> was expectedValue". The same applies, as far as I can see, to the
>>>>> other #assert:equals: calls.
>>>>
>>>> Which is a  counter-intuitive order for me...
>>>> Is that ansi?
>>>
>>> It's SUnit. I don't particularly like it, but that's the API.
>>>
>>> What I'd _really_ like is something like Phexample syntax, which would have
>>>
>>> (TextAttribute classFor: $d) should = TextDoIt.
>>>
>>> (Very RSpec-ish. Having said that, RSpec's moved away from should
>>> syntax because it requires monkey patching. So `foo should == :bar` is
>>> now `expect(foo).to eq(:bar)`. Translating that back into Smalltalk
>>> would probably look something like `Expect this: (TextAttribute
>>> classFor: $d) toEqual: TextDoIt`. Ack!)
>>
>> and there we are again:
>>        `Expect this: (TextAttribute classFor: $d) toEqual: TextDoIt`
>> can easily be:
>>        self assertThat: (TextAttribute classFor: $d) isEqualTo: TextDoIt
>> (which is near self assert: a equals: b, but the other way round again ;)
>>
>> What about
>> a) instvar named `it' and initialised to self or
>> b) method named #it that returns self (or what the user wants, like an "asserter")
>> and do
>>        it should: (TextAttribute classFor: $d) beEqualTo: TextDoIt
>> or
>>        self it should: (TextAttribute classFor: $d) beEqualTo: TextDoIt
>
> Would it be blasphemy to have a global or class called It? It should:
> $a equal: $b.
>
>>>> I like the usage as in the example better..
>>>
>>> I agree. I just held my nose and adapted. Altering the API means never
>>> being sure that you changed everything, and when you get it wrong you
>>> make someone's life a misery because their debug error message, meant
>>> to _aid_ them, now _lies_ to them.
>>
>> HmHmmm. But frankly, most people do not look up the argument names and
>> just use it intuitively and they then “think” the system is lying (while
>> it is not)…
>
> I've burned myself enough times that I just remember that expected goes first.
>
> frank
>
>> Best
>>        -Tobias
>

Reply | Threaded
Open this post in threaded view
|

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

Frank Shearar-3
In reply to this post by Colin Putney-3
On 4 January 2014 00:14, Colin Putney <[hidden email]> wrote:

>
>
>
> On Fri, Jan 3, 2014 at 3:42 PM, Tobias Pape <[hidden email]> wrote:
>>
>> > Would it be blasphemy to have a global or class called It? It should:
>> > $a equal: $b.
>>
>> Strangely, I like it.
>
>
> Why? "It should a equal b" isn't a coherent sentence.
>
> SUnit doesn't try to make everything into an executable specification (which
> is a good thing), but at least "self assert: a equals: b" reads like fluent
> Smalltalk.

The problem is that #assert:equals: looks symmetrical, but it's not. I
don't like the "self" part of "self assert: a equals: b" just because
it doesn't add any information: it's only there because Smalltalk
doesn't support implicit self-sends (like Ruby or Newspeak).

Anyway, the reason I mention RSpec at all is that I like their move
away from monkey patching Object so that everything understands
:should. Instead, they now wrap an object up in an object that adds
expectation stuff. That's not a problem with SUnit, mostly. But I
guess #assert: kind've means two things: both an assertion of some
condition that must hold, and also as a testing tool.

I do nearly like Phexample's syntax
(http://smalltalkthoughts.blogspot.co.uk/2009/11/phexample-because-examples-expand-on.html),
and I think Niko Schwarz's "build examples on top of each other" idea
is great. We run Phexample under CI, but I'm not proposing that we
replace SUnit.

frank

> Colin

Reply | Threaded
Open this post in threaded view
|

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

Sean P. DeNigris
Administrator
Frank Shearar-3 wrote
I don't like the "self" part of "self assert: a equals: b" just because
it doesn't add any information
Wow, I thought *I* was a perfectionist… All that to eliminate the word "self" ;) If you really can't stand the "self", why not make It a class variable of TestCase? Then you can name the class something reasonable without sending a message.
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

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

Sean P. DeNigris
Administrator
In reply to this post by Casey Ransberger-2
Casey Ransberger-2 wrote
I think keeping SUnit as simple as possible in the core system is the best plan
This is a tough one. After using Smalltalk for a few years now, and coming from Ruby where I used Cucumber and RSpec heavily, I have come to the opposite conclusion: if there is a place to include everything and the kitchen sick, it's for testing. I find myself frequently not bothering to test because I sit down to write the test, and realize that without mocks/stubs/Phexample-building-on-last-scenario built in, I either don't know how to do it, or it's not worth the effort. And the extra image size seems less important because this presumably would all be unloaded for production anyway.
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

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

Frank Shearar-3
In reply to this post by Sean P. DeNigris
On 4 January 2014 14:04, Sean P. DeNigris <[hidden email]> wrote:
> Frank Shearar-3 wrote
>> I don't like the "self" part of "self assert: a equals: b" just because
>> it doesn't add any information
>
> Wow, I thought *I* was a perfectionist… All that to eliminate the word
> "self" ;) If you really can't stand the "self", why not make It a class
> variable of TestCase? Then you can name the class something reasonable
> without sending a message.

It's one of the few things I actually _like_ about Ruby, that RSpec
has such a nice DSL. I'm not a huge fan of Cucumber (it's possible the
next few months will either make me hate or love it yet: it's in heavy
use at my new job), so I'm not talking about a language completely
different to the host language. It's just that, sometimes, like here,
I miss Ruby's implicit receivers.

But as Colin points out, using something like It is a bit "uncanny
valley". 'It' is close enough to English that the difference between
It and English is annoying. I suppose one could have `Assert that: a
equals: b`.

I don't know that it's worth writing yet another testing DSL, given
SUnit and Phexample already.

frank

Reply | Threaded
Open this post in threaded view
|

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

timrowledge
You might try something like

[thisTest result] mustBeLike: expectedResult

tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Fractured Idiom:- PRO BOZO PUBLICO - Support your local clown



Reply | Threaded
Open this post in threaded view
|

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

Colin Putney-3
In reply to this post by Frank Shearar-3



On Sat, Jan 4, 2014 at 12:04 PM, Frank Shearar <[hidden email]> wrote:
 
 
It's one of the few things I actually _like_ about Ruby, that RSpec
has such a nice DSL. I'm not a huge fan of Cucumber (it's possible the
next few months will either make me hate or love it yet: it's in heavy
use at my new job), so I'm not talking about a language completely
different to the host language. It's just that, sometimes, like here,
I miss Ruby's implicit receivers.

Weird. That's the thing I dislike about Ruby. It makes it so easy to play around with the appearance of code that the Ruby community has become obsessed with DSLs. It's gotten to the point that libraries and frameworks are designed more with an eye to a cool DSL than to simplicity or expressivity or performance.  On the other hand, simply knowing Ruby, the language, is no longer sufficient to be able to read code and understand it, you also have to know the semantics of the DSL being used. Since they're never documented, that means reverse engineering (without a decent debugger) the weird execution environment they've set up to make the DSL work, or reading blog posts and mailing lists from the last 3 years to find an explanation of the DSL.

I much prefer the Smalltalk community's tendency to build layers of abstraction, while sticking to idiomatic Smalltalk. DSLs have their uses, but I prefer to see them implemented with a well-defined grammar and a parser. That gives a lot more syntactic freedom in the design of the DSL and makes it much easier to understand what's happening at runtime.

Ok, rant over, back to testing.
 
But as Colin points out, using something like It is a bit "uncanny
valley". 'It' is close enough to English that the difference between
It and English is annoying. I suppose one could have `Assert that: a
equals: b`.

I find the question of syntax for expression of expectations is a distraction from the real task of testing software. Writing good tests is *hard*, but the difficulty has little to do with syntax. It's more a question of factoring the functionality such that testing is simple and effective, and writing tests that get to the essence of the expected behaviour, rather than implementation details. If you get that right, the form the tests take doesn't matter.

Colin


Reply | Threaded
Open this post in threaded view
|

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

Frank Shearar-3
On 4 January 2014 23:50, Colin Putney <[hidden email]> wrote:

>
>
>
> On Sat, Jan 4, 2014 at 12:04 PM, Frank Shearar <[hidden email]>
> wrote:
>
>>
>>
>> It's one of the few things I actually _like_ about Ruby, that RSpec
>> has such a nice DSL. I'm not a huge fan of Cucumber (it's possible the
>> next few months will either make me hate or love it yet: it's in heavy
>> use at my new job), so I'm not talking about a language completely
>> different to the host language. It's just that, sometimes, like here,
>> I miss Ruby's implicit receivers.
>
>
> Weird. That's the thing I dislike about Ruby. It makes it so easy to play
> around with the appearance of code that the Ruby community has become
> obsessed with DSLs. It's gotten to the point that libraries and frameworks
> are designed more with an eye to a cool DSL than to simplicity or
> expressivity or performance.  On the other hand, simply knowing Ruby, the
> language, is no longer sufficient to be able to read code and understand it,
> you also have to know the semantics of the DSL being used. Since they're
> never documented, that means reverse engineering (without a decent debugger)
> the weird execution environment they've set up to make the DSL work, or
> reading blog posts and mailing lists from the last 3 years to find an
> explanation of the DSL.
>
> I much prefer the Smalltalk community's tendency to build layers of
> abstraction, while sticking to idiomatic Smalltalk. DSLs have their uses,
> but I prefer to see them implemented with a well-defined grammar and a
> parser. That gives a lot more syntactic freedom in the design of the DSL and
> makes it much easier to understand what's happening at runtime.
>
> Ok, rant over, back to testing.

Yes. It's not just implicit receivers here, it's also instance_eval
and friends. And "external" DSLs make it clear in what language (hence
what semantics) you're working at any given point.

To be clear, I'm not talking about RSpec's it "should do stuff" {}
syntax. I'm talking about the language used to express assertions.
#assert:equals: is OK (other than it doesn't tell you where you should
put the expected and actual values). It's just not particularly slick.

>> But as Colin points out, using something like It is a bit "uncanny
>> valley". 'It' is close enough to English that the difference between
>> It and English is annoying. I suppose one could have `Assert that: a
>> equals: b`.
>
>
> I find the question of syntax for expression of expectations is a
> distraction from the real task of testing software. Writing good tests is
> *hard*, but the difficulty has little to do with syntax. It's more a
> question of factoring the functionality such that testing is simple and
> effective, and writing tests that get to the essence of the expected
> behaviour, rather than implementation details. If you get that right, the
> form the tests take doesn't matter.

But how can such a reasonable statement lead to endless flame wars, I
ask you? "With sufficient experience, the particular testing syntax
isn't important."

#assert:, #assert:equals: probably aren't ugly enough to warrant
revisiting. It's just... well, they're OK. They're not slick, but as
you point out, writing tests in the first place is much harder than
slickness in the testing syntax.

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.

frank

> Colin

Reply | Threaded
Open this post in threaded view
|

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

Colin Putney-3



On Sun, Jan 5, 2014 at 9:05 AM, Frank Shearar <[hidden email]> 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




Reply | Threaded
Open this post in threaded view
|

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

Chris Muller-3
In reply to this post by Colin Putney-3
>> It's one of the few things I actually _like_ about Ruby, that RSpec
>> has such a nice DSL. I'm not a huge fan of Cucumber (it's possible the
>> next few months will either make me hate or love it yet: it's in heavy
>> use at my new job), so I'm not talking about a language completely
>> different to the host language. It's just that, sometimes, like here,
>> I miss Ruby's implicit receivers.
>
>
> Weird. That's the thing I dislike about Ruby. It makes it so easy to play
> around with the appearance of code that the Ruby community has become
> obsessed with DSLs. It's gotten to the point that libraries and frameworks
> are designed more with an eye to a cool DSL than to simplicity or
> expressivity or performance.  On the other hand, simply knowing Ruby, the
> language, is no longer sufficient to be able to read code and understand it,
> you also have to know the semantics of the DSL being used. Since they're
> never documented, that means reverse engineering (without a decent debugger)
> the weird execution environment they've set up to make the DSL work, or
> reading blog posts and mailing lists from the last 3 years to find an
> explanation of the DSL.
>
> I much prefer the Smalltalk community's tendency to build layers of
> abstraction, while sticking to idiomatic Smalltalk. DSLs have their uses,
> ... snip...

Yes.  I've always liked how everything we do in Smalltalk is built on
an aggregation of just 3 or 4 concepts, and that's it.  THAT is pretty
slick in itself.  Anything above that is "magic" and should pay
_really_ good ROI to justify its existence (e.g., way more than simply
aesthetics).  Another example I can think of are those new special
inst-vars in Pharo (having trouble remembering the name, "slots?") to
define all sorts of RDBMS-style checks, etc.  I would rather do that
simply via the same few Smalltalk concepts as everything else.
Instantiation, setting state, and message-sending..

Reply | Threaded
Open this post in threaded view
|

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

Colin Putney-3



On Sun, Jan 5, 2014 at 5:28 PM, Chris Muller <[hidden email]> wrote:
 
Yes.  I've always liked how everything we do in Smalltalk is built on
an aggregation of just 3 or 4 concepts, and that's it.  THAT is pretty
slick in itself.

Agreed.

I suppose the appropriate term for the Smalltalk community would be "domain-specific vocabulary." We don't create a a separate language, with its own syntax and grammar, but we do tend to create to create a coherent system of nouns and verbs (classes and messages) that draw directly from the problem domain. Let's all write slick DSVs!

Colin


Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
In reply to this post by Colin Putney-3



On Fri, Jan 3, 2014 at 4:14 PM, Colin Putney <[hidden email]> wrote:



On Fri, Jan 3, 2014 at 3:42 PM, Tobias Pape <[hidden email]> wrote:
> Would it be blasphemy to have a global or class called It? It should:
> $a equal: $b.

Strangely, I like it.

Why? "It should a equal b" isn't a coherent sentence. 

So

So should a equal b ;-)


And

Thus

[And so thus is not an endorsement of this idea from me..]
 

SUnit doesn't try to make everything into an executable specification (which is a good thing), but at least "self assert: a equals: b" reads like fluent Smalltalk.

Colin






--
best,
Eliot


cbc
Reply | Threaded
Open this post in threaded view
|

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

cbc
On Fri, Jan 10, 2014 at 2:39 PM, Eliot Miranda <[hidden email]> wrote:



On Fri, Jan 3, 2014 at 4:14 PM, Colin Putney <[hidden email]> wrote:



On Fri, Jan 3, 2014 at 3:42 PM, Tobias Pape <[hidden email]> wrote:
> Would it be blasphemy to have a global or class called It? It should:
> $a equal: $b.

Strangely, I like it.

Why? "It should a equal b" isn't a coherent sentence. 

So

So should a equal b ;-)

maybe

So a should equal b

 


Reply | Threaded
Open this post in threaded view
|

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

Frank Shearar-3
On 10 January 2014 23:38, Chris Cunningham <[hidden email]> wrote:

> On Fri, Jan 10, 2014 at 2:39 PM, Eliot Miranda <[hidden email]>
> wrote:
>>
>>
>>
>>
>> On Fri, Jan 3, 2014 at 4:14 PM, Colin Putney <[hidden email]> wrote:
>>>
>>>
>>>
>>>
>>> On Fri, Jan 3, 2014 at 3:42 PM, Tobias Pape <[hidden email]> wrote:
>>>>
>>>> > Would it be blasphemy to have a global or class called It? It should:
>>>> > $a equal: $b.
>>>>
>>>> Strangely, I like it.
>>>
>>>
>>> Why? "It should a equal b" isn't a coherent sentence.
>>
>>
>> So
>>
>> So should a equal b ;-)
>>
> maybe
>
> So a should equal b

That, sadly, doesn't work, because here a is a message send to So.
What you need is a message taking a (and b) as parameters, which
requires two words before the word "a". I'm kind've leaning towards
Assert: Assert that: a equals: b.

In RSpec, changing the assertion language means not having to monkey
patch. In our case, TestCase does a whole pile of stuff. One of those
things is a DSL (domain specific vocab, as Colin put it - maybe even
"domain specific jargon") in the form of #assert: and friends. Pulling
that out into (say) Assert means factoring things better. JUnit also
did this, AFAIK, when they pulled in the Hamcrest matchers. (Assert
isn't a novel idea, btw: I've stolen it from NUnit:
Assert.IsTrue(proposition), Assert.AreEqual(a, b).)

frank

Reply | Threaded
Open this post in threaded view
|

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

Colin Putney-3



On Sat, Jan 11, 2014 at 9:14 AM, Frank Shearar <[hidden email]> wrote:
 
That, sadly, doesn't work, because here a is a message send to So.
What you need is a message taking a (and b) as parameters, which
requires two words before the word "a". I'm kind've leaning towards
Assert: Assert that: a equals: b.

In RSpec, changing the assertion language means not having to monkey
patch. In our case, TestCase does a whole pile of stuff. One of those
things is a DSL (domain specific vocab, as Colin put it - maybe even
"domain specific jargon") in the form of #assert: and friends. Pulling
that out into (say) Assert means factoring things better. JUnit also
did this, AFAIK, when they pulled in the Hamcrest matchers. (Assert
isn't a novel idea, btw: I've stolen it from NUnit:
Assert.IsTrue(proposition), Assert.AreEqual(a, b).)

It's true; it would separate the machinery for running tests (TestCase and friends) from the vocabulary for expressing expectations . Node.js does this nicely, and there's a selection of both test runners and assertion libraries that you can mix and match. 

However, using a global like that makes customizing the vocabulary awkward. You'd have to add class-side extension methods to Assert, possibly leading to extension conflicts between different test packages. 

One idea is to wrap the value being verified in an assertion proxy. It would forward messages to the object being examined, and intercept the answer. If the answer is false, it raises a TestFailure, other wise it wraps the answer and returns it. That would enable things like:

it := Assertion for: [3 + 4].
it > 6.
it = 7.
it < 8.
it + 1 = 8.
it negated = -7.

Then you could make a custom wrapper if you wanted more abstract assertions:

it := EnvironmentAssertion for: 
    [(Environment named: #test)
        exportSelf;
       bind: #Griffle to: Object new;
      yourself].

it exports: #Griffle.

That's kind of neat, but I suspect it breaks down when you have non-trivial tests. It's tough to beat the simple #assert:.

Colin