Testing code is very important and leads to more well-thought-out designs and more stable codebases. But how do we test javascript applications? Tools like Sinon.js, Mocha, and Chai can alleviate some of the pain as we try to bring testing benefits into our applications
11. 11
Mocking with Sinon & Proxyquire
• Use Mocks in unit testing for:
• Stability
• Speed
• Accuracy
• Proxyquire for Mock Injection
• Sinon for creating Mocks
Hi, I’m Andy Winder, and I work here at Message Systems as one of the engineers working on NodeJS APIs, and I wanted to talk today about some of the ways you can test your software, and go through some quick examples of testing JavaScript.
There are 3 main reasons for why we even want to do this whole testing business. We want to be able to ensure the quality of the code as we write it. Testing makes us think of how we’re writing code, and how people will interface with that code (either internally as developers or externally) as users. We want to be able to ensure our code is stable, and that any changes we make to the system don’t have any knock-on effects. We want to be able to refactor code and make sure it still maintains the same external interface. And we also want the security that we are able to change our systems and code without the whole thing blowing up in the future.
A test is a really simple construct, with lots of complexity that ends up coming around it. But at it’s core, testing is really just two parts…
The Subject is something that you want to introspect in your test. It’s usually some kind of output from the code you’re testing. If you’re testing a function, it might be the return value. If you’re testing a system, it might a variable that you look up in a database, or a string of text that you grab off the screen.
The Assertion is what you want to confirm about the subject of the test. You might want to confirm the value is equal to something, or you might want to confirm that it isn’t an error. If the assertion passes, that means your system is behaving as you expect it to. When an assertion fails, that means something is not working correctly within your code.
Three main kinds of testing: Unit testing, Integration Testing, Functional Testing. We write unit tests to make sure that individual objects can be interacted with, in isolation, the way we expect. Integration testing makes sure our objects can be consumed and used by other parts of the system in a stable way. Functional testing makes sure that our system as a whole works as expected in the same way that an end user is going to us the system.
JavaScript has a great ecosystem of tools for testing. Mocha, and alternatively Jasmine, are great test runners. They provide command line tools for running tests, they can help bootstrap environments, and provide different test result outputs to let you know what is passing and failing. Chai is an assertion library that provides the language for writing your tests. Sinon helps you write unit tests, while Protractor helps you test out your Angular apps. All these tools operate both independently and cooperatively with each other.
Imagine we have a method called getVehicleCost that we want to test. It takes in a parameter for the type of vehicle and returns the cost of that vehicle, or an error if we don’t know anything about the vehicle argument. So our tests need to be able to test the conditions that we know about, and the conditions that we don’t know about. We pass in expected arguments, car and boat, and then try to trick the function up by passing something that it doesn’t know about.
But what about asynchronous code? It’s going to be harder to write tests, right?
By handling the “done” function argument in your tests, you can control when the test case is done, and then use that to wait for asynchronous tests to finish up.
Mocking is a technique that is commonly used in unit testing. Remember before we talked about the purpose of unit testing as testing individual units of code, like objects, in isolation. If you have code that depends on third party services like MySQL, or a REST API somewhere, then you would want to replace interactions with those services with a fake, or “mock”, service. This way, you’re testing the unit by itself, rather than its interactions with the full system. This will help you write really fast test suites, that are very dependable, and have less dependencies than when you go to test your full system.
Sinon is a tool that can help with creating mocks. Think back to our example of async testing, where we queried MySQL . We had a call to get a MySQL connection object, then a call to query the database. We can use proxyquire to replace the calls to the MySQL module, and then use “yields” in our query mock to simulate the asynchronous callback from the database. Now our tests don’t rely on even having MySQL set up, and they don’t require any of the connection time & querying time that would normally need to take place. Over time this will save tons of time and is very useful for unit testing, and meeting the goals of unit tests being very stable & predictable.
So to recap, there’s 3 main types of testing: Unit testing, for fine-grained testing of individual modules in our codebases. Integration testing, for seeing how those individual modules connect with each other and start to form the basis for a functioning system. And functional testing, for testing full codebases in the ways users will interact with the system. Mocha, Sinon, and Proxyquire form the basis for really solid unit testing in Node.JS and in frontend / angular codebases. And we got to dig in a little on some examples of how these tests can look when testing out some simple code that connects to MySQL. Thanks for coming out today! Any questions?