About the announcements model for SUnit

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

About the announcements model for SUnit

Nicolás Papagna Maldonado
Hi everyone!

Lately I've been playing with/digging into the announcements model for SUnit, and have a couple of questions about it.

I'm trying to understand the model and I am by no means an expert to it. Any pointers/references/feedback is appreciated.

1) As expected TestCaseEnded is notified after a test case is run in TestResult>>#runCase:, but after some tests I've noticed that the announcement (which is created with the TestResult instance as collaborator) is sent before the passing test case is added to the TestResult instance. That means that one gets notified that a test case has been run successfully, but when inspecting the result, that test case won't be there:

runCase: aTestCase
        [
        aTestCase announce: TestCaseStarted withResult: self.
        aTestCase runCase.
        aTestCase announce: TestCaseEnded  withResult: self.
        self addPass: aTestCase
]
                on: self class failure , self class skip, self class warning, self class error
                do: [:ex | ex sunitAnnounce: aTestCase toResult: self]

Is this the expected behavior?

2) When a test case does not pass (for whatever reason), the failure is handled and the TestResult instance is updated, but a TestCaseEnded announcement is not sent. So there's a chance that you'd get a TestCaseStarted announcement, but never receive a TestCaseEnded announcement if it didn't pass:

runCase: aTestCase
        [
        aTestCase announce: TestCaseStarted withResult: self.
        aTestCase runCase.
        aTestCase announce: TestCaseEnded  withResult: self.
        self addPass: aTestCase]
                on: self class failure , self class skip, self class warning, self class error
                do: [:ex | ex sunitAnnounce: aTestCase toResult: self]

Is this the expected behavior?

3) When a TestSuiteEnded is announced (TestResult>>#updateResultsInHistory), the announcement instance is created passing in the TestCase subclass as result. So, when sending #testResult to the annoucement, one does not get a TestResult instance (as expected) but the TestCase subclass.

updateResultsInHistory
        |classesToNotify|
        classesToNotify:= Set new.
        #(#passed #failures #errors) do: [ :status |
                (self perform: status) do: [ :testCase |
                        classesToNotify add:testCase class.
                        self class updateTestHistoryFor: testCase status: status ] ].
        classesToNotify do:[:cl |
                cl historyAnnouncer announce: (TestSuiteEnded result: cl)]

4) I've read an old post about using a Dictionary instead of storing the TestResult instance as history, and it seemed like that was the intended design. The only issue I see there is that there could be potentially duplicated code in writing the interpretation of that dictionary (ie. #passed, #failures, #defects, etc..). Has anyone worked with TestCase results history before? if So, which was your approach to do it?

Cheers,
Nico PM

Reply | Threaded
Open this post in threaded view
|

Re: About the announcements model for SUnit

Max Leske
Hi Nicolás,

> On 26 Nov 2015, at 00:43, Nicolás Papagna Maldonado <[hidden email]> wrote:
>
> Hi everyone!
>
> Lately I've been playing with/digging into the announcements model for
> SUnit, and have a couple of questions about it.
>
> I'm trying to understand the model and I am by no means an expert to it. Any
> pointers/references/feedback is appreciated.
>
> 1) As expected TestCaseEnded is notified after a test case is run in
> TestResult>>#runCase:, but after some tests I've noticed that the
> announcement (which is created with the TestResult instance as collaborator)
> is sent before the passing test case is added to the TestResult instance.
> That means that one gets notified that a test case has been run
> successfully, but when inspecting the result, that test case won't be there:
>
> runCase: aTestCase
> [
> aTestCase announce: TestCaseStarted withResult: self.
> aTestCase runCase.
> *aTestCase announce: TestCaseEnded  withResult: self.
> self addPass: aTestCase*]
> on: self class failure , self class skip, self class warning, self class
> error
> do: [:ex | ex sunitAnnounce: aTestCase toResult: self]
>
> Is this the expected behavior?

No, of course not. But what do you mean by “inspecting the result”? The TestResult instance should contain the finished test regardless. Say, you inspect the TestResult before the test has been added, then refreshing the inspector (or opening a new one) should correctly show the test case in the result because it has been added in the mean time.

I guess that switching those two statements wouldn’t hurt though.

>
> 2) When a test case does not pass (for whatever reason), the failure is
> handled and the TestResult instance is updated, but a TestCaseEnded
> announcement is not sent. So there's a chance that you'd get a
> TestCaseStarted announcement, but never receive a TestCaseEnded announcement
> if it didn't pass:
>
> runCase: aTestCase
> [
> *aTestCase announce: TestCaseStarted withResult: self.*
> aTestCase runCase.
> aTestCase announce: TestCaseEnded  withResult: self.
> self addPass: aTestCase]
> on: self class failure , self class skip, self class warning, self class
> error
> do: [:ex | *ex sunitAnnounce: aTestCase toResult: self*]
>
> Is this the expected behavior?

I agree. TestCaseEnded should be announced in all cases.

>
> 3) When a TestSuiteEnded is announced (TestResult>>#updateResultsInHistory),
> the announcement instance is created passing in the TestCase subclass as
> result. So, when sending #testResult to the annoucement, one does not get a
> TestResult instance (as expected) but the TestCase subclass.
>
> updateResultsInHistory
> |classesToNotify|
> classesToNotify:= Set new.
> #(#passed #failures #errors) do: [ :status |
> (self perform: status) do: [ :testCase |
> classesToNotify add:testCase class.
> self class updateTestHistoryFor: testCase status: status ] ].
> *classesToNotify do:[:cl | *
> cl historyAnnouncer announce: (*TestSuiteEnded result: cl*)]

That should probably be “TestSuiteEnded testCase: cl”. If you look at the subscribers to TestSuiteEnded you’ll see that #result is used to retrieve the test case. So those senders would need to be updated. but yes, since there is a #testCase: selector it’s pretty bad that the selector used is #result:.

>
> 4) I've read an old post about using a Dictionary instead of storing the
> TestResult instance as history, and it seemed like that was the intended
> design. The only issue I see there is that there could be potentially
> duplicated code in writing the interpretation of that dictionary (ie.
> #passed, #failures, #defects, etc..). Has anyone worked with TestCase
> results history before? if So, which was your approach to do it?
>
> Cheers,
> Nico PM
>
>

Thanks for looking at that code! It’s been lying around for ages and everyone fears it (at least that’s my impression :) ).

Cheers,
Max

>
>
>
> --
> View this message in context: http://forum.world.st/About-the-announcements-model-for-SUnit-tp4863569.html
> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>


Reply | Threaded
Open this post in threaded view
|

Re: About the announcements model for SUnit

EuanM
When Kent Beck was doing Smalltalk consulting, he wouldn't give SUnit
to his client corporation.

He would get any dev group to write it themselves from the concepts.

All of which means I don't think we need to be too precious about the
code - we don;t need to fear it   :-)

On 26 November 2015 at 11:13, Max Leske <[hidden email]> wrote:

> Hi Nicolás,
>
>> On 26 Nov 2015, at 00:43, Nicolás Papagna Maldonado <[hidden email]> wrote:
>>
>> Hi everyone!
>>
>> Lately I've been playing with/digging into the announcements model for
>> SUnit, and have a couple of questions about it.
>>
>> I'm trying to understand the model and I am by no means an expert to it. Any
>> pointers/references/feedback is appreciated.
>>
>> 1) As expected TestCaseEnded is notified after a test case is run in
>> TestResult>>#runCase:, but after some tests I've noticed that the
>> announcement (which is created with the TestResult instance as collaborator)
>> is sent before the passing test case is added to the TestResult instance.
>> That means that one gets notified that a test case has been run
>> successfully, but when inspecting the result, that test case won't be there:
>>
>> runCase: aTestCase
>>       [
>>       aTestCase announce: TestCaseStarted withResult: self.
>>       aTestCase runCase.
>>       *aTestCase announce: TestCaseEnded  withResult: self.
>>       self addPass: aTestCase*]
>>               on: self class failure , self class skip, self class warning, self class
>> error
>>               do: [:ex | ex sunitAnnounce: aTestCase toResult: self]
>>
>> Is this the expected behavior?
>
> No, of course not. But what do you mean by “inspecting the result”? The TestResult instance should contain the finished test regardless. Say, you inspect the TestResult before the test has been added, then refreshing the inspector (or opening a new one) should correctly show the test case in the result because it has been added in the mean time.
>
> I guess that switching those two statements wouldn’t hurt though.
>
>>
>> 2) When a test case does not pass (for whatever reason), the failure is
>> handled and the TestResult instance is updated, but a TestCaseEnded
>> announcement is not sent. So there's a chance that you'd get a
>> TestCaseStarted announcement, but never receive a TestCaseEnded announcement
>> if it didn't pass:
>>
>> runCase: aTestCase
>>       [
>>       *aTestCase announce: TestCaseStarted withResult: self.*
>>       aTestCase runCase.
>>       aTestCase announce: TestCaseEnded  withResult: self.
>>       self addPass: aTestCase]
>>               on: self class failure , self class skip, self class warning, self class
>> error
>>               do: [:ex | *ex sunitAnnounce: aTestCase toResult: self*]
>>
>> Is this the expected behavior?
>
> I agree. TestCaseEnded should be announced in all cases.
>
>>
>> 3) When a TestSuiteEnded is announced (TestResult>>#updateResultsInHistory),
>> the announcement instance is created passing in the TestCase subclass as
>> result. So, when sending #testResult to the annoucement, one does not get a
>> TestResult instance (as expected) but the TestCase subclass.
>>
>> updateResultsInHistory
>>       |classesToNotify|
>>       classesToNotify:= Set new.
>>       #(#passed #failures #errors) do: [ :status |
>>               (self perform: status) do: [ :testCase |
>>                       classesToNotify add:testCase class.
>>                       self class updateTestHistoryFor: testCase status: status ] ].
>>       *classesToNotify do:[:cl | *
>>               cl historyAnnouncer announce: (*TestSuiteEnded result: cl*)]
>
> That should probably be “TestSuiteEnded testCase: cl”. If you look at the subscribers to TestSuiteEnded you’ll see that #result is used to retrieve the test case. So those senders would need to be updated. but yes, since there is a #testCase: selector it’s pretty bad that the selector used is #result:.
>
>>
>> 4) I've read an old post about using a Dictionary instead of storing the
>> TestResult instance as history, and it seemed like that was the intended
>> design. The only issue I see there is that there could be potentially
>> duplicated code in writing the interpretation of that dictionary (ie.
>> #passed, #failures, #defects, etc..). Has anyone worked with TestCase
>> results history before? if So, which was your approach to do it?
>>
>> Cheers,
>> Nico PM
>>
>>
>
> Thanks for looking at that code! It’s been lying around for ages and everyone fears it (at least that’s my impression :) ).
>
> Cheers,
> Max
>
>>
>>
>>
>> --
>> View this message in context: http://forum.world.st/About-the-announcements-model-for-SUnit-tp4863569.html
>> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: About the announcements model for SUnit

EuanM
Sandi Metz on this issue of fear: https://youtu.be/npOGOmkxuio?t=1077
(You might want to back up a little  after watching these 15 seconds,
to get a some context)

On 30 November 2015 at 00:51, EuanM <[hidden email]> wrote:

> When Kent Beck was doing Smalltalk consulting, he wouldn't give SUnit
> to his client corporation.
>
> He would get any dev group to write it themselves from the concepts.
>
> All of which means I don't think we need to be too precious about the
> code - we don;t need to fear it   :-)
>
> On 26 November 2015 at 11:13, Max Leske <[hidden email]> wrote:
>> Hi Nicolás,
>>
>>> On 26 Nov 2015, at 00:43, Nicolás Papagna Maldonado <[hidden email]> wrote:
>>>
>>> Hi everyone!
>>>
>>> Lately I've been playing with/digging into the announcements model for
>>> SUnit, and have a couple of questions about it.
>>>
>>> I'm trying to understand the model and I am by no means an expert to it. Any
>>> pointers/references/feedback is appreciated.
>>>
>>> 1) As expected TestCaseEnded is notified after a test case is run in
>>> TestResult>>#runCase:, but after some tests I've noticed that the
>>> announcement (which is created with the TestResult instance as collaborator)
>>> is sent before the passing test case is added to the TestResult instance.
>>> That means that one gets notified that a test case has been run
>>> successfully, but when inspecting the result, that test case won't be there:
>>>
>>> runCase: aTestCase
>>>       [
>>>       aTestCase announce: TestCaseStarted withResult: self.
>>>       aTestCase runCase.
>>>       *aTestCase announce: TestCaseEnded  withResult: self.
>>>       self addPass: aTestCase*]
>>>               on: self class failure , self class skip, self class warning, self class
>>> error
>>>               do: [:ex | ex sunitAnnounce: aTestCase toResult: self]
>>>
>>> Is this the expected behavior?
>>
>> No, of course not. But what do you mean by “inspecting the result”? The TestResult instance should contain the finished test regardless. Say, you inspect the TestResult before the test has been added, then refreshing the inspector (or opening a new one) should correctly show the test case in the result because it has been added in the mean time.
>>
>> I guess that switching those two statements wouldn’t hurt though.
>>
>>>
>>> 2) When a test case does not pass (for whatever reason), the failure is
>>> handled and the TestResult instance is updated, but a TestCaseEnded
>>> announcement is not sent. So there's a chance that you'd get a
>>> TestCaseStarted announcement, but never receive a TestCaseEnded announcement
>>> if it didn't pass:
>>>
>>> runCase: aTestCase
>>>       [
>>>       *aTestCase announce: TestCaseStarted withResult: self.*
>>>       aTestCase runCase.
>>>       aTestCase announce: TestCaseEnded  withResult: self.
>>>       self addPass: aTestCase]
>>>               on: self class failure , self class skip, self class warning, self class
>>> error
>>>               do: [:ex | *ex sunitAnnounce: aTestCase toResult: self*]
>>>
>>> Is this the expected behavior?
>>
>> I agree. TestCaseEnded should be announced in all cases.
>>
>>>
>>> 3) When a TestSuiteEnded is announced (TestResult>>#updateResultsInHistory),
>>> the announcement instance is created passing in the TestCase subclass as
>>> result. So, when sending #testResult to the annoucement, one does not get a
>>> TestResult instance (as expected) but the TestCase subclass.
>>>
>>> updateResultsInHistory
>>>       |classesToNotify|
>>>       classesToNotify:= Set new.
>>>       #(#passed #failures #errors) do: [ :status |
>>>               (self perform: status) do: [ :testCase |
>>>                       classesToNotify add:testCase class.
>>>                       self class updateTestHistoryFor: testCase status: status ] ].
>>>       *classesToNotify do:[:cl | *
>>>               cl historyAnnouncer announce: (*TestSuiteEnded result: cl*)]
>>
>> That should probably be “TestSuiteEnded testCase: cl”. If you look at the subscribers to TestSuiteEnded you’ll see that #result is used to retrieve the test case. So those senders would need to be updated. but yes, since there is a #testCase: selector it’s pretty bad that the selector used is #result:.
>>
>>>
>>> 4) I've read an old post about using a Dictionary instead of storing the
>>> TestResult instance as history, and it seemed like that was the intended
>>> design. The only issue I see there is that there could be potentially
>>> duplicated code in writing the interpretation of that dictionary (ie.
>>> #passed, #failures, #defects, etc..). Has anyone worked with TestCase
>>> results history before? if So, which was your approach to do it?
>>>
>>> Cheers,
>>> Nico PM
>>>
>>>
>>
>> Thanks for looking at that code! It’s been lying around for ages and everyone fears it (at least that’s my impression :) ).
>>
>> Cheers,
>> Max
>>
>>>
>>>
>>>
>>> --
>>> View this message in context: http://forum.world.st/About-the-announcements-model-for-SUnit-tp4863569.html
>>> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>>>
>>
>>