Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Let's Get Testable: An Introduction to Unit Testing

Let's Get Testable: An Introduction to Unit Testing

Presented at :
CSS Dev Conf New Orleans, 2014
Javascript Summit 2015

Front-end unit testing is beginning to emerge as a best practice for building Javascript-heavy web applications. Testing can seem daunting or a bit confusing at first for some developers, but once understood it becomes an invaluable tool for building stable applications.

- What are unit tests?
- Why should I be writing tests?
- What tools do I have available for writing front-end unit tests?
- I love it! How do I get started?

A5af583190a73a7d94255c6f79cde415?s=128

Alicia Sedlock

October 13, 2014
Tweet

Transcript

  1. Let’s Get Testable! An Introduction to Unit Testing

  2. Prologue

  3. We make more than “websites”
 now.

  4. Back-end practices are influencing our path.

  5. And along comes testing.

  6. Unit Testing

  7. “Units” are small pieces of code, typically at the function

    level.
  8. Validate an email address Perform a calculation Set user information

  9. Unit tests help prevent regressions.

  10. Unit tests document your code.

  11. Test-Driven Development

  12. You need team buy-in.

  13. Popular Tools • Jasmine (http://jasmine.github.io/) • Mocha (http://visionmedia.github.io/mocha/) • QUnit

    (http://qunitjs.com/) • CasperJS (http://casperjs.org/) • …and others!
  14. An example. (We’ll be using Jasmine.)

  15. A calculator app.

  16. Describe Your Test Suite describe(“Calculator Operations”, function () {! !

    });
  17. Write A Test Description describe(“Calculator Operations”, function () {! !

    ! it(“Should add two numbers”, function () {! ! ! });! ! });
  18. Expectations and Matchers describe(“Calculator Operations”, function () {! ! !

    it(“Should add two numbers”, function () {! ! ! ! Calculator.init();! ! ! ! ! ! var result = Calculator.addNumbers(7,3);! ! ! ! expect(result).toBe(10);! ! ! });! ! });
  19. Expectations and Matchers describe(“Calculator Operations”, function () {! ! !

    it(“Should add two numbers”, function () {! ! ! ! Calculator.init();! ! ! ! ! ! var result = Calculator.addNumbers(7,3);! ! ! ! expect(result).toBe(10);! ! ! expect(result).not.toBe(null);! ! ! });! ! });
  20. Add More Tests … ! it(“Should add two numbers”, function

    () {! ! ! Calculator.init();! ! ! ! var result = Calculator.addNumbers(7,3);! ! ! ! expect(result).toBe(10);! ! ! expect(result).not.toBe(null);! ! });! ! ! it(“Should subtract two numbers”, function () {! ! ! Calculator.init();! ! ! ! var result = Calculator.subtractNumbers(20,4);! ! ! ! expect(result).toBe(16);! ! ! expect(result).not.toBe(null);! ! });! …
  21. Hmm… … ! it(“Should add two numbers”, function () {!

    ! ! Calculator.init();! ! ! ! var result = Calculator.addNumbers(7,3);! ! ! ! expect(result).toBe(10);! ! ! expect(result).not.toBe(null);! ! });! ! ! it(“Should subtract two numbers”, function () {! ! ! Calculator.init();! ! ! ! var result = Calculator.subtractNumbers(20,4);! ! ! ! expect(result).toBe(16);! ! ! expect(result).not.toBe(null);! ! });! …
  22. Setup and Breakdown describe(“Calculator Operations”, function () {! ! !

    beforeEach(function () {! ! ! ! ! ! Calculator.init();! ! ! });! ! });
  23. Setup and Breakdown describe(“Calculator Operations”, function () {! ! !

    beforeEach(function () {! ! ! ! ! ! Calculator.init();! ! ! });! ! ! afterEach(function () {! ! ! ! ! ! Calculator.remove();! ! ! });! ! });
  24. Spies … ! it(“Should store the results of operations”, function

    () {! ! ! });! …
  25. Spies … ! it(“Should store the results of operations”, function

    () {! ! ! ! expect(Calculator.currentValue).toBe(0);! ! ! });! …
  26. Spies … ! it(“Should store the results of operations”, function

    () {! ! ! ! expect(Calculator.currentValue).toBe(0);! ! ! ! spyOn(Calculator, “updateCurrentValue”);! ! ! });! …
  27. Spies … ! it(“Should store the results of operations”, function

    () {! ! ! ! expect(Calculator.currentValue).toBe(0);! ! ! ! spyOn(Calculator, “updateCurrentValue”);! ! ! ! Calculator.addNumbers(7,10);! ! ! ! expect(Calculator.updateCurrentValue).toHaveBeenCalled();! ! ! });! …
  28. Spies … ! it(“Should store the results of operations”, function

    () {! ! ! ! expect(Calculator.currentValue).toBe(0);! ! ! ! spyOn(Calculator, “updateCurrentValue”);! ! ! ! Calculator.addNumbers(7,10);! ! ! ! expect(Calculator.updateCurrentValue).toHaveBeenCalled();! ! ! ! ! ! expect(Calculator.updateCurrentValue)! ! ! ! ! .toHaveBeenCalledWith(17);! ! ! });! …
  29. Spies … ! it(“Should store the results of operations”, function

    () {! ! ! ! expect(Calculator.currentValue).toBe(0);! ! ! ! spyOn(Calculator, “updateCurrentValue”);! ! ! ! Calculator.addNumbers(7,10);! ! ! ! expect(Calculator.updateCurrentValue).toHaveBeenCalled();! ! ! ! ! ! expect(Calculator.updateCurrentValue)! ! ! ! ! .toHaveBeenCalledWith(17);! ! ! ! expect(Calculator.currentValue).toBe(17);! ! ! });! …
  30. Asynchronous Operations

  31. .done() … ! it(“Should test async”, function (done) {! !

    ! ! ! ! var foo = 0;! ! ! foo++;! ! ! ! setTimeout(function () {! ! ! ! expect(foo).toBe(1);! ! ! ! done();! ! ! }, 100);! ! ! });! …
  32. .done() … ! ! ! beforeEach(function (done) {! ! !

    ! ! ! Calculator.setUserInfo(“aliciasedlock”);! ! ! ! setTimeout(function () {! ! ! ! done();! ! ! }, 4000);! ! ! });! ! ! it(“Should set the user information”, function () {! ! ! ! ! ! expect(Calculator.user).toBe(“Alicia”);! ! ! });! …
  33. .done() … ! ! ! beforeEach(function (done) {! ! !

    ! ! ! jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;! ! ! ! ! Calculator.setUserInfo(“aliciasedlock”);! ! ! ! setTimeout(function () {! ! ! ! done();! ! ! }, 9000);! ! ! });! ! ! it(“Should set the user information”, function () {! ! ! ! ! ! expect(Calculator.user).toBe(“Alicia”);! ! ! });! …
  34. Should I or Shouldn’t I…?

  35. … ! it(“Should store the results of operations”, function ()

    {! ! ! ! expect(Calculator.currentValue).toBe(0);! ! ! ! spyOn(Calculator, “updateCurrentValue”);! ! ! ! Calculator.addNumbers(7,10);! ! ! ! expect(Calculator.updateCurrentValue).toHaveBeenCalled();! ! ! ! ! ! expect(Calculator.updateCurrentValue)! ! ! ! ! .toHaveBeenCalledWith(17);! ! ! ! expect(Calculator.currentValue).toBe(17);! ! ! });! …
  36. … ! it(“Should store the results of operations”, function ()

    {! ! ! ! expect(Calculator.currentValue).toBe(0);! ! ! ! spyOn(Calculator, “updateCurrentValue”);! ! ! ! Calculator.addNumbers(7,10);! ! ! ! var result = $(“span#result”).text();! ! ! ! expect(result).toBe(“17”);! ! });! …
  37. Testing Code vs. Testing jQuery

  38. And if I already have an app?

  39. • As your modify code, write a test.

  40. • As your modify code, write a test. • Adding

    new features? Write tests!
  41. • As your modify code, write a test. • Adding

    new features? Write tests! • Incorporate into code reviews.
  42. End-To-End Testing

  43. Can a user get from point A to point B?

  44. Registration flow Checkout process Credential-specific functionality

  45. Automated Testing for QA

  46. Real Browser vs. Headless Browser

  47. Real Browser • Selenium (http://www.seleniumhq.org/) • Karma (http://karma-runner.github.io/0.12/index.html)

  48. Headless Browser • Karma (http://karma-runner.github.io/0.12/index.html) • PhantomJS (http://phantomjs.org/)

  49. “CSS Testing”…?

  50. We Could Mean… • Styling consistency • Malformed/unused CSS •

    CSS Regressions
  51. Styling Consistency • Object-Oriented CSS/Modular Development • SASS/LESS • Pattern

    Libraries/Living Style Guides
  52. Malformed/unused CSS • CSS code styling guide (http://cssguidelin.es/) • CSS

    Lint (https://github.com/CSSLint/csslint) • UnCSS (https://github.com/giakki/uncss)
  53. CSS Regression Testing?

  54. CSS Regression Tools • Wraith (https://github.com/BBC-News/wraith) • Resemble.js (http://huddle.github.io/Resemble.js/) •

    …plus PhantomCSS • …plus CasperJS
  55. This can help with RWD testing.

  56. This concept is still very young.

  57. We can define what CSS testing means, if we want

    it.
  58. Epilogue

  59. 1. It takes time.

  60. 2. Test time matters

  61. 3. You will still have bugs

  62. 4. Lots of build tool integrations!

  63. 5. Always keep improving

  64. Thank you JS Summit! Follow @aliciability for slides