Skip to main content

Unit Testing with the Jasmine JS


Recently had the opportunity to do pair programming on a project at work. Paring has proven to be invaluable in passing knowledge over to other developers on the team. It is in this paring that I was exposed to Jasmine test behavior development.
Jasmine was developed at Pivotal Labs back in 2001, and was the first unit testing framework for JavaScript. I won't go into why you should be doing test or behavior driven development, but if your company has adopted the Agile methodology, Jasmine fits nicely into the flow of the Agile process. It gives you the additional security knowing that if at some point in the future someone updates your JavaScript, unless the test suite is updated as well things will begin to break.

The Suite or Spec

Conceptually, a suite or spec is a bunch of related tests clubbed together with an expected result or outcome. Suites or specs are defined with the global "describe" function. This describes what is being tested. The describe function takes 2 parameters, a text string and a call back function. The cool thing is the description attribute of the function can be derived from the description of an agile story. "....we need to display to the user a red check mark in addition to highlighting the field in red that has an incorrect or improper value submitted." From this we can begin writing our suite or spec.
I sometimes like to nest the describe function to coincide with the user's actions. Inside the describe method we add our "it" method, which again takes 2 parameters, a text string for the description and a call back function.
As you can see we have added the agile story; "On visiting the search page When errors return on submit Should add the fieldErrorBorder class to the fields that return with the error class" to the code. It also acts as your code comment. At this point I set up our fixtures and call backs to the JavaScript source file I'm writing the test against. I have created the fieldErrorBorder class that contains the input field error and the red check mark and placed it in the CSS file so it can be added using the JavaScript source file when the error condition occurs.

The source file

I'm also importing the "lodash" JavaScript library. Lodash is really excellent at array handling and array I/O.  
In my source file I'm using the "Revealing Module Pattern" to expose the methods to the spec file. Simply add your existing functions to the object literal, the "Return", and reference it as such: searchErrors.setBorderForErrors().

Acceptance criterion

Acceptance tests are directly related to the software requirements specs. Trace-ability between requirements and implementation as well as between requirements and acceptance tests is key to test driven development.

Going forward keep in mind:
  • Test written first
  • Given [something is going to happen]
  • When [something happens]
  • Then [we expect this to happen]
  • Tests are written to reflect business value.
  • Think in plain old English description of what you are doing or intending to do.
  • Tests are written first tested and failed, code written after.
Test driven development and Behavior driven development is now a de-facto standard for developers. I have just touched the surface of the power of Jasmine, Jasmine jQuery, and Lodash. If written correctly, any changes, accidental or otherwise, to your JavaScript will happily throw an error thus saving the developer countless headaches and hours of lost productivity. Estimate correctly during grooming. ½ day to write the JavaScript may now be 1 day to write the JavaScript and the spec. Write the test first. Make it fail. Consider how you will expose your methods to the web and to the spec. Keep it simple. Code the test, run the test, code, run the test, rinse and repeat…etc. Fix errors pre commit. Clear runner cache often, run from build or command line. Happy development!

Reference

Comments

Popular posts from this blog

:nth-child structural pseudo-class selectors

There are 4 pseudo-class expressions that are part of the :nth-child pseudo-class. Structural pseudo-class selectors target HTML elements based on the DOM tree. Basically, elements that cannot easily be targeted by simple selectors or combinations of selectors. What makes pseudo-classes so handy is the ability style elements dynamically based on its position in the DOM. :nth-of-type(N) :nth-last-child(N) :nth-child(N) :nth-last-of-type(N) :nth-of-type(N) selector My favorite of the 4 is the :nth-of-type(N) selector. The nth-of-type selector allows you to select child elements of a parent based on the particular type of the element, for example every 5th "li" element in a list. You can select even or odd elements, or the nth (order number) child in the group of elements. The class accepts the argument "n" which can can be a keyword, a number, or strings "odd", "even", or an expression "-n+3". Let's look at a simple but ef

The ICMP protocol

Let's look into the ICMP protocol. Specifically, ping and traceroute. ICMP is the Internet Control Message Protocol and is a component of the IP Layer. Basically, used by hosts to communicate diagnostic network layer information that is carried in the IP payload. It communicates error messages which are acted on by the IP layer or the UDP or TCP protocols. All of the exercises were carried out using the open source network protocol analyzer "Wireshark". www.wireshark.org Describe in detail the protocols ARP and ICMP. ARP is the Address Resolution Protocol is similar to that of DNS. Where DNS resolves IP addresses to domain names, ARP resolves network layer IP addresses to link layer MAC addresses. In order to send a datagram the source must give the adaptor the IP address and the MAC address. For example, host A wants to send a packet to host B. Host A uses a cached ARP table to look up the IP address for any existing records of host B's MAC address. If the MA

Creating triggers

Triggers are SQL statements which are stored with the intention of being activated or fired when an event associated with a database table occurs. This could be any event including an INSERT, UPDATE and DELETE. Lets begin by creating a few simple insert triggers CREATE a trigger on the ORDERLINE table for the insert event. The trigger will update the corresponding PRODUCT record QTY_ORDERED by adding the value of QTY to QTY_ORDERED. CREATE TRIGGER tr_qty_ordered_value_insert ON Orderline FOR INSERT AS BEGIN UPDATE product SET QTY_ORDERED = QTY_ORDERED + ((SELECT qty from INSERTED) * (SELECT unitprice from INSERTED)) WHERE product.ProductID = (SELECT ProductID from INSERTED); END; Command(s) completed successfully. CREATE a trigger on the ORDERLINE table for the delete event. The trigger will update the corresponding PRODUCT record QTY_ORDERED by subtracting the value of QTY FROM QTY_ORDERED. CREATE TRIGGER tr_qty_ordered_value_delete ON Orde