Testing static and prototype variables

383 views
Skip to first unread message

re-newbie

unread,
Dec 12, 2010, 1:26:23 AM12/12/10
to Jasmine
After a 10 year hiatus, I'm doing some JavaScript again and found your
test framework and am really liking it. Very clean. Keep up the
great work.

In reintroducing myself to the language I was writing some test
scripts just to see how things behaved and ran into an interesting
problem, when trying to test the state of static and class prototype
variables, having to do with the delayed execution of "it" blocks in
the test runner. The problem is that the statement calling the static
method would execute before the "it" blocks testing the initial values
at the top of the test. So the tests that fail are actually *before*
the statement that changes the values. Here's a shortened version of
my test:

describe("fun with statics", function() {

var sa1 = new SiteAuditor();

SiteAuditor.ResetDefaultDate(2010, 10, 10);

it("sa1 prototype date should be the initial value",
function() {
expect(sa1.DefaultDate.getDate()).toEqual(10); /******
FAILS because date is 1 ********/
});

SiteAuditor.ResetDefaultDate(2001, 1, 1)

it("sa1 prototype date should be the set value", function() {
expect(sa1.DefaultDate.getDate()).toEqual(1);
});
/* ...more tests on prototype state... */
});

But if I remove the line that calls the second ResetDefaultDate and
replace the last "it" block with the following, it all works:

it("sa1 prototype date should be the set value", function() {
this.addMatchers({
toEqualAfterReset: function() {
SiteAuditor.ResetDefaultDate(2001, 1, 1);;
return this.actual.DefaultDate.getDate() == 1;
}
});
expect(sa1).toEqualAfterReset(1);
/* ...more tests on prototype state... */

This seems a bit contrived, but I couldn't figure out another way to
get the test to pass both sections. Keep in mind this is a pared down
version of a real test I want to write that tracks the state changes
of a couple prototype variable based on other actions in my app.

So my question is, is there a better way to write tests like this
where a statement within a "describe" block executes before the "it"
blocks and throws off your results? I'm probably just too used to the
regular old AssertEquals type of tests and haven't caught on to the
BDD idiom yet.

Sorry for the long post. Any help or advice is appreciated. Thanks.

Tom

Frank Schwieterman

unread,
Dec 12, 2010, 3:35:03 AM12/12/10
to jasmi...@googlegroups.com
There might be some confusion, you have setup code that is outside a
beforeEach() block. Code within a beforeEach() block will run per
test, the code directory within the describe() is only run once. So
typically you only have 'var' expressions directly within a describe
block indicate the scope of variables, and then you set the values and
do other setup within a beforeEach() block.

> --
> You received this message because you are subscribed to the Google Groups "Jasmine" group.
> To post to this group, send email to jasmi...@googlegroups.com.
> To unsubscribe from this group, send email to jasmine-js+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/jasmine-js?hl=en.
>
>

Frank Schwieterman

unread,
Dec 12, 2010, 3:36:00 AM12/12/10
to jasmi...@googlegroups.com
Typo: replace "the code directory within the describe()" with "the
code directly within the describe()"

re-newbie

unread,
Dec 12, 2010, 11:17:22 AM12/12/10
to Jasmine
That works fine for instance base tests where it's OK to have the var
not be the same object instance for each it-expects block. I do want
that code to run only once. I need to make sure the object (sa1 in my
case) is the same object each time I check its value(s). I'm testing
a progression of behaviors on the same object.

BTW, I did try putting the call to the reset method inside the second
"it" block, but got the same result. The second Reset method executes
before the first expect() at the top. Does that help make it clearer
as to what I'm trying to do?

Tom.

Frank Schwieterman

unread,
Dec 12, 2010, 7:34:58 PM12/12/10
to jasmi...@googlegroups.com
The thing is, the code in the describe() blocks will not work for
test setup. When Jasmine runs your tests, if I recall correctly from
the last time I looked at the code, it runs the the contents of the
describe() blocks first, in order to discover all the tests blocks and
setup methods. So ALL the code directly within a describe() block is
ran before any code within a beforeEach/afterEach/it() block.
So before the first it() blocks run, both of your calls to
SiteAuditor.ResetDefaultDate() have already ran.
Code directly within the describe block really should only be "var"
statements, unless you have some setup that should only run once
before all tests (I wouldn't write tests with shared setup though).

I think you have some alternatives. The simplest:

it("fun with statics", function() {

var sa1 = new SiteAuditor();

SiteAuditor.ResetDefaultDate(2010, 10, 10);
expect(sa1.DefaultDate.getDate()).toEqual(10);

SiteAuditor.ResetDefaultDate(2001, 1, 1)
expect(sa1.DefaultDate.getDate()).toEqual(1);
});

I would frown on this implementation because I've been taught to
only test 1 thing per test, and that test is testing two. Thats just
something I've been taught though as part of tDD, I don't know the
rule still applies for BDD in particular.

I think a preferable implementation would be:


describe("fun with statics", function() {

var sa1;

beforeEach(function() {


sa1 = new SiteAuditor();
SiteAuditor.ResetDefaultDate(2010, 10, 10);

});

it("calling the static effects existing instances", function() {
expect(sa1.DefaultDate.getDate()).toEqual(10);
});

it("the second call to the static overwrites the first", function() {
SiteAuditor.ResetDefaultDate(2001, 1, 1)
expect(sa1.DefaultDate.getDate()).toEqual(1);
});
});


So this is two tests, and there will be two instances of
SiteAuditor() created, but it is testing the progression of behaviors.
This is slightly different from your original sample though in that
there is no intermediate call to sa1.DefaultDate.getDate() before the
second call to SiteAuditor.ResetDefaultDate. If getDate() has side
effects you need to include in your test progression, then the second
it() would need to be:

it("the second call to the static overrides the first", function() {
sa1.DefaultDate.getDate()
SiteAuditor.ResetDefaultDate(2001, 1, 1)
expect(sa1.DefaultDate.getDate()).toEqual(1);
});

re-newbie

unread,
Dec 14, 2010, 10:04:53 PM12/14/10
to Jasmine
Responses inline below...

On Dec 12, 7:34 pm, Frank Schwieterman <fschw...@gmail.com> wrote:
> ...it runs the the contents of the
> describe() blocks first, in order to discover all the tests blocks and
> setup methods.  So ALL the code directly within a describe() block is
> ran before any code within a beforeEach/afterEach/it() block.

*That* really helped. I missed the nuance of the order things happen
reading the docs. Thanks.

>   So before the first it() blocks run, both of your calls to
> SiteAuditor.ResetDefaultDate() have already ran.

right. That's what I was trying to get away from.

>   Code directly within the describe block really should only be "var"
> statements, unless you have some setup that should only run once
> before all tests (I wouldn't write tests with shared setup though).
>
>   I think you have some alternatives.  The simplest:
>
> it("fun with statics", function() {
>
>   var sa1 = new SiteAuditor();
>
>   SiteAuditor.ResetDefaultDate(2010, 10, 10);
>   expect(sa1.DefaultDate.getDate()).toEqual(10);
>
>   SiteAuditor.ResetDefaultDate(2001, 1, 1)
>   expect(sa1.DefaultDate.getDate()).toEqual(1);
>
> });

This was the key part I was missing. My mental model was treating the
it() block as if it were an Assert statement in the TDD world, since
that's where the description was for what was being tested, and I was
thinking of the expect()toEqual() part as just the *kind* of assert
the it() block was implementing. When really, the expect() part is
the assert equivalent (not literally, but semantically) and the it()
is kinda like the test method. I just need to put a different image
in my head about how Jasmine fits together.

>
>   I would frown on this implementation because I've been taught to
> only test 1 thing per test, and that test is testing two.  Thats just
> something I've been taught though as part of tDD, I don't know the
> rule still applies for BDD in particular.

Yep. It's a good rule-of-thumb, not a commandment. Sometimes you
just need to do something more than a single setup/assert combo. I've
been doing B/T DD for a long time now and sometimes it's just not
practical, or as clear, to split everything up; and that's OK. The
goal here is testing the things that can break so you can change
things confidently, *not* make sure every behavior has but one
expectation for the purity of the test. As always, the difference
between theory and practice is much closer in theory than in
practice. :-)

> (rest snipped...)

Thanks for the help Frank.

Tom.
Reply all
Reply to author
Forward
0 new messages