Re: [jasmine-js] Proposal: data provider pattern for Jasmine tests

374 views
Skip to first unread message

Joel McCracken

unread,
Aug 29, 2012, 1:43:43 AM8/29/12
to jasmi...@googlegroups.com

I already do things like this in my tests, so I think it is a good idea. Jasmine is
pretty lightweight though, so I'm not sure this kind of thing belongs in
it. It doesn't feel orthogonal to the rest of the library. However, I'm
all in favor of adding more stuff to jasmine (rspec style "let"
declarations, for example, would be an amazing feature).

Of course, I have no say at all. Nice code.

JP <jph...@gmail.com> writes:

> Hi,I've lately started to use a pattern to DRY up my Jasmine tests. I call this pattern "Data Provider" (I copied the feature name from PHPUnit, which is were I first learned about it). The basic premise of a data provider is to feed a test with multiple test values to avoid repeating your test code over and over. Imagine you have a validation test for a username that looks like this:describe("username validation", function() { it("should return true for valid usernames", function() { expect(validateUserName("abc")).toBeTruthy(); expect(validateUserName("longusername")).toBeTruthy(); expect(validateUserName("john_doe")).toBeTruthy(); }) it("should return false for invalid usernames", function() { expect(validateUserName("ab")).toBeFalsy(); expect(validateUserName("name_too_long")).toBeFalsy(); expect(validateUserName("no spaces")).toBeFalsy(); expect(validateUserName("inv*alid")).toBeFalsy(); })})I don't really like to repeat many expectations within one test block. With the data provider pattern it would look like this:describe("username validation", function() { using("valid values", ["abc", "longusername", "john_doe"], function(value){ it("should return true for valid usernames", function() { expect(validateUserName(value)).toBeTruthy(); }) }) using("invalid values", ["ab", "name_too_long", "no spaces", "inv*alid"], function(value){ it("should return false for invalid usernames", function() { expect(validateUserName(value)).toBeFalsy(); }) })})I implemented a very simple function called "using" that can work with Jasmine out of the box:<span style="font-family: 'courier new', monospace; ">function using(name, values, func){</span> for (var i = 0, count = values.length; i < count; i++) { if (Object.prototype.toString.call(values[i]) !== '[object Array]') { values[i] = [values[i]]; } func.apply(this, values[i]); jasmine.currentEnv_.currentSpec.description += ' (with "' + name + '" using ' + values[i].join(', ') + ')'; }}You can see the attachments for additional examples and you can also check out a demo at http://jphpsf.com/jasmine-data-provider/What do you guys think of this pattern? I've searched for an existing solution but could not find one. Do you think this would be a good addition to Jasmine itself? I'll be happy to work on a pull request :)Cheers!JP

Davis W. Frank

unread,
Aug 29, 2012, 1:51:50 AM8/29/12
to jasmi...@googlegroups.com
Definitely interesting approach. I personally feel that having each of the invalid cases called out in a separate it block allows you to name them more specifically. Such as:

it "should consider too short names invalid"
it "should consider names with spaces to be invalid"

DRYing up specs is a touchy subject as each codebase has different tolerances for what keeps the test suite clean enough to read without too much duplication. As you can see, I prefer a slightly damp codebase. :)

I don't think we'd be interested in taking this into Jasmine Core at this time. 

However, I strongly encourage you to blog about this add-on. Expand your email a bit, post it, and I'll give it a retweet from the official account.

--dwf


--
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.




--
thx,
--dwf

JP

unread,
Aug 29, 2012, 12:34:34 PM8/29/12
to jasmi...@googlegroups.com
Excellent! Thank you for the feedback. Very good points. I actually have a draft for a blog post. It will go live tomorrow.

Cheers

JP

unread,
Aug 30, 2012, 11:29:22 AM8/30/12
to jasmi...@googlegroups.com
Hi Davis,

I just published a blog post with all the details at:

http://blog.jphpsf.com/2012/08/30/drying-up-your-javascript-jasmine-tests/

Cheers!


JP 

Davis W. Frank

unread,
Aug 30, 2012, 10:28:56 PM8/30/12
to jasmi...@googlegroups.com
Retweeted!

Thanks for using Jasmine and helping the community!

--dwf



Cheers!


JP 

--
You received this message because you are subscribed to the Google Groups "Jasmine" group.
To view this discussion on the web visit https://groups.google.com/d/msg/jasmine-js/-/l96DrWAPl_QJ.

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.



--
thx,
--dwf

Martin Häcker

unread,
Aug 31, 2012, 4:09:56 AM8/31/12
to jasmi...@googlegroups.com
> I just published a blog post with all the details at:
>
> http://blog.jphpsf.com/2012/08/30/drying-up-your-javascript-jasmine-tests/

Just out of interest (and since the commenting facility on your blog doesn't work for me) why not go with something like this:

it("should accept valid usernames", function() {
_(['foo', 'bar', 'baz']).each(function(each) {
expect(isValidUsername(each)).toBeTruthy()
})
})

Seems simpler and to express the same point of dryness. And it can easily become even more dry by using e.g. coffeescript:

it "should accept valid usernames", ->
_(['foo', 'bar', 'baz']).each (each) ->
expect(isValidUsername(each)).toBeTruthy()

The only point might be that during debugging it you don't get the error message to immediately tell you which of the usernames has gone wrong, but that hasn't really slowed me down too much yet.

Cheers,
Martin

Joel McCracken

unread,
Aug 31, 2012, 3:59:14 PM8/31/12
to jasmi...@googlegroups.com
I've done it similarly, except with  

  _(['foo', 'bar', 'baz']).each(function(uname) {
     it("should accept valid username "+uname, function() {
        expect(isValidUsername(uname)).toBeTruthy()
     })
  })

However, there *is* benefit to having more declarative code. 

--
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.

JP

unread,
Aug 31, 2012, 4:00:06 PM8/31/12
to jasmi...@googlegroups.com
Hi

Thanks for the feedback. I am not sure why the commenting system did not work.

Anyway, I think your syntax is an interesting approach as well. For the debugging issue in case of failure, I guess you could wrap the it in the each block:

_(['foo', 'bar', 'baz']).each (each) -> 
  it "should accept valid usernames with #{each}", -> 
        expect(isValidUsername(each)).toBeTruthy() 

And with coffeescript string interpolation, customizing the message is quite elegant.

Cheers

JP

unread,
Aug 31, 2012, 4:00:57 PM8/31/12
to jasmi...@googlegroups.com
Well, it looks like Joel beat me to it ;)

chandrasekar arunachalam

unread,
Dec 2, 2018, 1:55:45 PM12/2/18
to Jasmine
Thanks for the clear post, and do you know why this pattern is still not incorporated in the core lib ?

chandrasekar arunachalam

unread,
Dec 2, 2018, 1:55:45 PM12/2/18
to Jasmine
Guys are we still on it ?
Reply all
Reply to author
Forward
0 new messages