Now that you have an awesome testing environment with Testem set up, you need to actually start writing tests. This is where people begin to feel daunted. “Oh no, I need to learn another library” comes to many people’s minds and because this library doesn’t add any cool features to your site or application, it doesn’t seem like much fun. We need to brush that aside, though, because testing libraries tend to have very, very simple APIs and can be learned within a couple hours of tinkering. Let me prove it to you.
Jasmine has a few main global functions in its arsenal. These functions are global mostly so that the code is simpler to read. You can actually nearly read it like a sentence. The first function we’ll talk about is
describe. This function is used to organize your tests into suites. A suite is just a fancy name for a collection of tests so that you can organize your tests into related blocks. Here’s how
describe looks in action:
As you can see it takes two arguments: A string that is used to identify a suite and a function that contains the actual test code. The string is used in the test runner to hierarchically display which tests passed and which ones failed. The function can contain any code you want it to contain; however, you need to use specific Jasmine-supplied functions in order to get anything to show up in the test results, as we’ll explain in the next section.
Suites can be nested inside of each other too. This allows you fine-grained organization of code into hierarchical structures. I usually have an initial
describe block for an object and then have nested
describe blocks for each of its methods, like so:
Now that we have the code organized into suites, which generally represent the nouns, we need to write some tests (aka specs), which are the verbs. We do this with
it. This is how
As you can see,
it is nested within a
describe block so that the spec’s verb can be associated with a noun that commits the verb. So,
describe is where you say what the object is that does something and
it is where you say what it does. Within
it is where you actually test to see if the verb was completed successfully. We’ll discuss how to do that in the next section.
Before we take a look at that, though, take a close look at the comments I placed inside the
it block. I separated it into two different sections: setup and checking. First you set up and run the necessary functions. Then you test to see if everything worked out the way it should have. This is the “standard” way of doing a test and is the pattern you should always follow. Obviously, though, if there’s nothing to set up, just skip that part and start checking.
As I just said a moment ago, within
it is where you do your actual testing. Essentially, you are just checking to see if the outcome is the same as you expected. Jasmine uses
expect as the name of the function that is used to test the expected outcomes.
expect takes a single argument, which can be any value, and then returns an object that has a bunch of methods called matchers. The matchers are what test the value to determine if it was correct. It’s hard to explain this without code, so take a look:
expect and it gave us an object with the matcher methods on it. We chose to use the
toBe matcher and passed in 2 as the argument.
toBe just compares the value given to
expect with the value given to it using
===. Essentially this is what is happening for Jasmine in this situation:
If you don’t use
expect and a matcher, your tests will always be considered passing tests, unless there is an error thrown (there is at least one exception, which I’ll discuss later). If you really want to be sure your tests are passing/failing, then you need to use
expect. You can use
expect as many times as you want per
it block, but you should try to keep them minimal. If you need to call
expect a lot, it probably means that the functions you’re testing are doing too many things. If any of the
expects fail, the entire spec will fail.
There are a ton of matchers, and it doesn’t really pay to go over them all here.
toBe is a very common one and is definitely one of the easiest to understand and can be used in most situations, but you should see the Jasmine documentation for the rest of the matchers. You can also create custom matchers, but I won’t go over that here. They just allow you to write matchers that simplify how you write your tests so that they are more domain-specific.
Two more of the functions that Jasmine provides are
afterEach. These aren’t necessary, but can help keep your code DRY. You use them inside of your
describe blocks and before your
it blocks. They each take a function as their sole parameter, and these functions are run before/after each of the specs, including the specs nested inside deeper
describe blocks. This way, if you have some common setup or teardown procedures, you can place them inside one of these functions and only write it once instead of repeating it within each of your
it blocks. Here’s an example:
The final thing we’ll be talking about today is the
this keyword. You can of course use closures and local variables for containing all of your data that will be passed around to each of your functions, but this isn’t the only way. Each function you pass around (such as to
it, and others) is run in the same context. This means that you can define something in
this.someObj = … and you can access that object within
this.someObj. It’s entirely up to you which technique you use, but I still wanted you to see your options so you have a choice.
That’s all I’m going to talk about today. Next week we’ll discuss a few more things that Jasmine offers us, such as Spies,
jasmine.any, and asynchronous testing. I hope that you are looking forward to it and spend a little time practicing your Jasmine unit testing before we get into it. God bless and happy coding!