Help with SUnit
John M McIntosh
johnmci at smalltalkconsulting.com
Thu Jan 22 18:20:02 UTC 2004
When I attempt this with a 3.7a image and at change set 5566 I first
use the open menu to open a Test Runner 'SUnit Camp Smalltalk 3.1 Test
runner; which shows my JMMTestCase, which I select, then I click on the
RUN button I get my JMMTestCase failed, I click on the failing method,
I get a notifier up that when I debug I see
openDebuggerOnFailingTestMethod
"SUnit has halted one step in front of the failing test method. Step
over the 'self halt' and
send into 'self perform: testSelector' to see the failure from the
beginning"
I then proceed and I get TestFailure: Assertion failed
with this on the stack
assert: aBoolean
aBoolean ifFalse: [self signalFailure: 'Assertion failed']
If I click down to the testMe method I see the instance variables are
testSelector: #testMe
stream: a WriteStream
I'm not sure which image or SUnit version you are using, you might want
to try with 3.7a and see what happens since I was unable to reproduce
your results.
Also if I might comment on your
> tearDown
> stream _ nil
which technically performs the destruction of the WriteStream instance.
Sometimes folks coming from the C/C++ world feel they must explicitly
destroy all variables after usage, this isn't required in GC languages
since the variable will get reclaimed once it's no longer accessible.
In this case the WriteStream instance goes away either when the
instance of your TestCase is forgotten, or in setUp when we reassign
what the instance variable stream is referring to. Although this is a
minor issue I have seen smalltalk systems where dozens of instance
variables are set to null and attempts made to call each of them to
cleanup things, when a domain object is 'deleted' That results in lots
of cycles taken up doing needless work.
Explicit deletion can led to bugs, however I'll temper that with the
comment that some objects might need closure if they don't have Weak
Reference support to ensure system resources are surrendered at GC
time, or if the frameworks involved don't forget about them
automatically at some point.
In this case the stream _ nil isn't needed. However if it was a file
based stream then a close should be done, mind you weak reference
support would ensure the file is closed automatically when the stream
was actually GCed even if you didn't do an explicit close.
> self halt in tearDown (feeling on dodgy ground now)
Please feel free to do that anywhere, why else would Smalltalkers ship
all the source other than so you can read/learn/fiddle, older
smalltalkers might recall (with distaste) when Digitalk and IBM hid
source code from us. Mind sticking a self halt anywhere can lead to
disaster, but it's a learning experience.
On Jan 22, 2004, at 9:27 AM, Michael Roberts wrote:
> I've got myself a bit confused with SUnit and was hoping someone might
> be able to help out. This feels like a bug but much of the time I
> just need to learn some more Squeak! I feel desperately stupid
> because I can't find what I'm doing wrong!
>
> I have a test class with one instance variable 'stream'. I have
> attached the file but it is easy enough to walk through its three
> methods.
>
> setUp
> stream _ WriteStream on: ''
>
> tearDown
> stream _ nil
>
> testMe
> self assert: stream notNil.
> stream nextPutAll: 'I have a cunning plan'.
> self assert: false
>
> The thing that is confusing me is this:
> 1) the test should fail on the last line. You can set this to true to
> check it passes.
>
> 2) SUnit brings up a debugger on the failing test but stream is nil so
> you can't get past the first line. I have started to walk through
> this code and below is my idea so far...
>
> TestCase>>runAsFailure: does a self setUp followed by self
> openDebuggerOnFailingTestMethod which in turn runs the test in its own
> process and attaches the debugger.
>
> 3) When the debugger runs, however, stream is nil as illustrated by
> the position of the debugger highlight and checking the object's
> state. I'm guessing that somewhere the test execution is stopped at
> the first error. this isn't the line that caused the assertion though.
>
> If I put some self halts into SUnit (probably a bad idea, I eventually
> get code simulation errors etc) I can run through the original
> execution of the test to see that it asserts on the last line. I can
> then watch the failed test get setup correctly and see a valid stream
> instance variable.
>
> 4) I get a valid instance variable by stepping into
> openDebuggerOnFailingTestMethod but can't go any further.
>
> 5) If I put a self halt in tearDown (feeling on dodgy ground now)
> something is sending tearDown to the test the instance after the
> debugger is opened on the failing test. I can then confirm that the
> test instance is now not valid.
>
> 6) If I look at the stack of what is sending tearDown it's coming from
> here
>
> runCaseAsFailure: aSemaphore
> [self setUp.
> self openDebuggerOnFailingTestMethod] sunitEnsure: [
> self tearDown.
> aSemaphore signal]
>
> which should be the same place that opened the debugger earlier.
>
> 7) how does the block to sunitEnsure: wait for
> openDebuggerOnFailingTestMethod to finish? It should just be a normal
> block being sent >>value.
>
> If openDebuggerOnFailingTestMethod waits until the debugger is closed
> then the ensure block shouldn't get called. If
> openDebuggerOnFailingTestMethod doesn't stop then the test instance
> gets clobbered by the ensure block?
>
> I'm a bit lost in this method!
>
> 8) surely I'm doing something daft right? :-)
>
> Cheers
> Mike
>
>
> <MikeIsConfusedTest.st>
>
--
========================================================================
===
John M. McIntosh <johnmci at smalltalkconsulting.com> 1-800-477-2659
Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com
========================================================================
===
More information about the Squeak-dev
mailing list
|