Showing posts with label Unit Testing. Show all posts
Showing posts with label Unit Testing. Show all posts

Thursday, April 28, 2016

Writing Web-Based Client-Side Unit-Tests with Jasmine and Blanket

Preface

When writing a website, or more often - a one page app - there is a need to test it, just like any other piece of code.

There are several types of tests, of course, including unit tests and integration tests.
While integration tests test flows of the entire application, end to end, and thus simulate user interaction (which requires special browser-based testing package), unit tests run specific functions.
However, when writing an entire application in JavaScript, running pieces of code is a bit more tricky.

On one hand, we are not used to writing unit tests in JavaScript, and run the tests completely in the browser. On the other hand, calling JavaScript code and then testing various members for values is much more easily done when written directly in JavaScript.

Luckily, the good people of the web has given us several JavaScript based packages for writing unit tests. I'll talk about Jasmine, and add some words about Blanket, that integrates with Jasmine to perform code-coverage.

Jasmine

Jasmine is a JavaScript based library to perform unit tests. It consists of several parts:
  1. The Runner
  2. Tests Framework
  3. Plug-ins

1. The Runner

The runner is an HTML file with base code that loads the tests framework and runs the tests. It will not do anything when you take it out-of-the-box. You have to add your own scripts in there, so consider it a template.

The base HTML looks like this:
<link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-2.0.0/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-2.0.0/jasmine.css">

<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine-html.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/boot.js"></script>

Next, you need to add your own application scripts:
<script type="text/javascript" src="src/myApp.js"></script>

And finally comes your tests scripts:
<script type="text/javascript" src="tests/myAppTestSpec.js"></script>

2. Tests Framework

Jasmine have several files that create the tests framework. The most basic ones are the one listed above, in the basic HTML example. Let's go over them quickly:

jasmine.js

The most basic requirement. This is the actual framework.

jasmine-html.js

This one is used to generate HTML reports. It is a requirement, even if you don't want HTML reports.

boot.js

This one was added in version 2.0 of Jasmine, and it performs the entire initialization process.


Writing Tests


Structure

The unit tests in Jasmine are called "Specs", and are wrapped in "Suites". It look like this:
describe("A suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

The describe function describes a test suite, while the it function specifies a test.
Note that those two get as parameters a name and a simple function block, and that the it block is being called in the body of the describe function block. This means you can store "global" members for each test suite. Also it means that the tested code comes inside the it block, along with any assertions.

Expectations (a.k.a. Asserts in other test suites)

When writing a unit test you expect something to happen, and you assert if it doesn't. While in other test suites you usually use the term Assert to perform such operation, in Jasmine you simply Expect something.

The syntax for expectations is straight forward:
expect(true).toBe(true);

There are many "matchers" you can user with the expect function, including but not limited to:
  • toBe - test the value to actually BE some object (using '===').
  • toEqual - test the value to EQUAL some other value.
  • toMatch - tests a string against a regular expression.
  • toBeDefined / toBeUndefined - compares the value against 'undefined'.
  • toBeTruthy / toBeFalsy - tests the value for JavaScript's truthiness or falsiness.
  • toThrow / toThrowError - if the object is a function, expects it to throw an exception.
You can also negate the expectation by adding not between the expect and the matcher.

Spies

You can also use Jasmine to test if a function has been called. In addition, you can (actually, need) to define what happens when the function is called. The syntax looks like this:
spyOn(someObject, "functionName").and.callThrough();
spyOn(someObject, "functionName").and.returnValue(123);
spyOn(someObject, "functionName").and.callFake( ... alternative function implementation ... );
spyOn(someObject, "functionName").and.throwError("Error message");
spyOn(someObject, "functionName").and.stub();
Then, you can check (expect) if the function was called using:
expect(someObject.functionName).toHaveBeenCalled();
or
expect(someObject.functionName).toHaveBeenCalledWith(... comma separated list of parameters ...);

More info

There are many features you can use with Jasmine. You can read all about it in the official documentation at http://jasmine.github.io/

3. Plug-ins

Well, I'll only talk about Blanket, the code coverage utility that integrates with Jasmine.

In the runner, add the following line before tests specs scripts, but after the application scripts:
<script type="text/javascript" src="lib/blanket.min.jsdata-cover-adapter="lib/jasmine-blanket-2_0.js"></script>

and that's it!

Below the test results report there will be the code coverage report.

The blanket.js package can be found at http://blanketjs.org/ and the adepter for Jasmine 2.x can be found at https://gist.github.com/grossadamm/570e032a8b144ec251c1 (unfortunately, blanket.js only comes pre-packaged with an adapter for Jasmine 1.x).




Happy Coding!

Monday, May 27, 2013

Apprenticeship Program


All professionals around the world need to be trained and software engineers aren't an exception.

Hence, we announce a unique program (and for sure the first in Israel) we are proud to kick off this week: a Software Development Apprenticeship Program.

PicSocut will hire and train apprentices; We will focus (but not limit) on clean code, reading/writing code, clean architecture, BDD, TDD, simple and business oriented designs, tools and best practices. In nutshell, all what you need to become a highly competent software engineer who cares and proud about his profession.

We are looking for couple of candidates to begin the program!

If you feel it's you, please feel free to send us your resume at jobs@picscout.com

Good Luck!



  

Thursday, April 5, 2012

Code Retreat at PicScout

At the end of January we've reserved some time from our busy schedule to conduct a code retreat at PicScout.
For that propose we invited a very special guest, who was visiting Israel as a guest of the Software Craftsmanship community: Corey Haines.

Corey introduced himself to the team and then outlined the code retreat day.
We were supposed to implement a short program, called Conway's Game of Life in continuous series of sessions, each introducing and emphasizing a different idea/angle in the coding craft.

According to Corey, the idea was to perfect our knowledge and coding techniques by concentrated practice. 



Just with the introduction, Corey mentioned very important thing: It is somehow a wrong perception that experienced/mature developers write perfect code. 
Actually their code isn't beautiful (nor perfect), but the difference between the un-experienced and highly experienced developers is that their code will be perfect enough
My own take on that is that only when you are an expert, only then you will be able to decide when this enough is enough (there are no rules, just experience and practice)
According to Corey, the purpose of the code retreat (to some degree) is to teach us how to seek a perfect enough code.

After a short introduction the fun began.




We coded in pairs for 45 min. 
At the end of each session we deleted the code and started over from scratch.
And yes, you're not mistaken; We deleted the code.
Somehow, during the history of our profession we learned the unwritten rule: 
Thee shell not delete any code.

Here is again my take on this: Deleting actually makes a lot of sense, since typing code isn't the real problem.
The real problem is reading (and maintaining) our code.

Therefore, the same writing 101 techniques apply when composing code. 
Write, Re-read then Re-read again. If it doesn't make sense Delete it. Start over. 

After deleting the code, we've reflected on what happened during the session. A few questions popped up and Corey provided short answers and directions.
In my opinion, the main idea was to let us to "find out" the right approach instead of providing a solid answer. 
Swapping pairs contributed to the diversity of the solutions. 
Each pair provided a unique solution and a unique approach that revealed different ways of solving a problem.

So what we did?

I. We started by exploring the problem. 
Conway's game of life is a nice problem that cannot be solved in 45 min. 
The first session was just to become familiar with the problem.
Needless to say that almost nobody (except the algorithm's team :) ) produced something coherent enough during this session.

II. Next we touched a sensitive topic, called a "better design". 
You know what it is when you call somebody else and tell him that this isn't how he should build his software (guess what happens a few weeks later when somebody else review your code). 
The idea in this session was that it is quite hard to find what is a "better" design. Therefore we discussed the 4 rules of simple design:

1. Tests Pass
2. Reveals Intent (good names)
3. No Duplication - repeat information and knowledge only once
4. Small (remove redundant, be lean and minimalist)

An interesting remark (with regards to 2) was that WE CAN use verbs to name classes.
Also here, some archaic (and not written rule) taught us that we should use only nouns as the class names. 
Why is that? If it makes sense, if it reveals the content then we shouldn't limit ourselves to those rules.

III. On our third session we touched Test First.
We discussed where from we should start (obviously, from an empty, null or default case). 
We discussed what we want to test or specifically what is the interface/action we would like to reveal during our test (a hint here will be: a tick() action that happens in the Conway's world)
We discussed how our test slowly and gradually reveal the interfaces and the behaviors of our objects (specifically we discussed why a cell needs to have a state)

IV. The fourth session introduced two pairing techniques.
a. A driver (who writes the code) and a navigator (who watches the driver)
b. A driver and a navigator are constantly exchanging their roles (like in a ping pong game)

The problem with the first technique is that it is done in a very statical way: The driver always drives and the navigator almost never touches a keyboard. 
This is obviously quite boring!

The Ping-Pong technique is a better implementation of the Driver/Navigator. There are two forms of a Ping-Pong pairing:
a. Driver: Writes a test. Navigator: Passes the test
b. Driver: Passes a test and writes the next test. Navigator. Passes the test and then writes the next test

Eventually in this session we used a MUTE ping pong style when a driver writes a test and a navigator passes the test.
In addition, Corey introduced the "find the loophole" - the navigator will strive to write a wrong implementation (though in a clean manner) and the driver will strive his best to write the failing tests.
IMO, it was the best session, since there in silence you can really discover the power of the test first and pair programming techniques.

V. In that  session Corey talked about the TDD and Test First techniques. 
Corey explained the difference between the two and how our design should be changed due to the use of the TDD.

In addition, we were introduced with the following constrains on our code:
Contraints:
1. If statements are disallowed (unless these are guard clauses). If statement is a form of procedural programming and usually can be seen as the simplest form of polymorphism.
2. Explicit looping (for, foreach) are disallowed.
3. No primitives across method passing
4. No method with more than 3 LOC (lines of code) 

I assume you guessed correctly, such constrains are really helping in creating more readable and maintainable code. 

VI.
We wrapped the day by asking 3 Questions. 

1. What if anything did you learn?
2. What if anything surprised you?
3. What if anything will you do differently moving forward.

I can definitely say that it was one of the most enjoyable days we had at PicScout and we surely learnt a great deal!






Monday, February 13, 2012

A Week of IL Tech Talks at PicScout

Sharing real life experience for the benefit of Israeli hi-tech community is one of the greatest things we have achieved during the last years.

Ori Lahav’s IL Tech Talks initiative definitely helped in promoting this in our community.
That’s why we happily hosted a full week of those tech talks at PicScout.

We learned a lot: From understanding client side performance, best development practices (here and here), scaling (here and here) to lean practices and management skills.

Amazingly, it appears that “good” things are somehow “reproduced” among the companies. The talks revealed that successful companies are build from the same “forces” in terms of practices and vision. These are exactly the same things we have done and continue to pursue at PicScout.

Unit testing, TDD and Continuous Delivery seems to free business and technology to move safely and together towards the goal. It was quite obvious from Wix’s and Outbrain’s experiences.

For us, being one of the scalable companies in Israel (in terms of billions image recognitions a month), it was very interesting to see others views on scalability.
Specifically (and personally), I would mention here the lecture by Eran Sandler.
Building a truly scalable architecture is hard. Sometimes, it isn’t even necessary till the right conditions are met. Eran’s lecture, introduced small and measured steps to gain scalability without re-writing the code.

Lean techniques (presented skillfully by Elad Sofer) made us to re-enforce our approach of continuous improvement. Building effective communication, seeking and eliminating waste and design for simplicity (yet “useful” products) are skills we all need to embrace and to grow.

Here are some (but not all) of our feedbacks:

Ilya: Once again I have got a validation on how Continuous Delivery and TDD help to create better software - talking about “Building a web infrastructure for 10M users”
Sharon: New ideas on management that will be tested soon ;) - talking about “Team Up”
Merav: Sometimes Agile principles perceived as the new management panacea; Understanding that those principles are here to serve you in a long term is what important - talking about “Lean Software Development”
Arik: I definitely learnt a few new best practices to make our web sites more effective - talking about “Web Performance 101”

We would like to thank all the presenters, who contributed from their own time to present and to share with us their real life experiences!








Thursday, December 29, 2011

ILTechTalks Week

During the second week of January, PicScout will host a week of IL Tech Talks.
We will have 2 talks a day starting from 16:30.

Please follow IL Tech Talks meet-up for more details.

Here's the agenda:


S - 8/1
M - 9/1
T - 10/1
W - 11/1
Th - 12/1
Team Up
(18:00)

The number of places is limited, so hurry up if you are interested.