|
| 1 | +# Introduction to testing |
| 2 | + |
| 3 | +We are now moving into the advanced concepts of backend web development. However, at this point of the bootcamp these concepts should not be completely unfamiliar to you either. You have seen what tests look like and how they're executed in all your previous assignments. Now it's time to understand them in detail. The objectives of this lesson are: |
| 4 | +1. Understanding tests and their importance |
| 5 | +2. Getting familiar with the syntax of test code |
| 6 | + |
| 7 | +## What is a test? |
| 8 | + |
| 9 | +In programming, a test refers to a piece of code that can be run to verify the |
| 10 | +behavior of a program. For example, if you write a function, and you want to be |
| 11 | +sure that it works for various inputs and outputs, you can write a test for this |
| 12 | +function. |
| 13 | + |
| 14 | +Tests themselves are also code. At larger companies, every piece of submitted code |
| 15 | +needs to submitted with a corresponding test. A general rule of thumb is that, |
| 16 | +if by mistake you change a line of your code so that the behavior is wrong, a test |
| 17 | +somewhere should fail, so that such a mistake can be caught. |
| 18 | + |
| 19 | +Tests are an important part of many companies' infrastructure for development. |
| 20 | +Generally, humans are not manually running these tests, though you may manually |
| 21 | +run some tests before sending a pull request or while working on the test itself. In a process called **continuous integration** (CI), these tests will usually automatically run after every pull request is proposed. This means that generally, if your code and pull request are not passing the tests, it cannot be merged in until fixed. |
| 22 | + |
| 23 | +There are many types of tests: unit tests, integration tests, smoke tests, |
| 24 | +and so on. In a later section, we will talk about some of these types of tests. |
| 25 | +Most commonly, we will refer to unit tests, which are the most frequent type of |
| 26 | +tests. |
| 27 | + |
| 28 | +## Why is testing important? |
| 29 | + |
| 30 | +You may think it is sufficient simply to manually test your code. |
| 31 | + |
| 32 | +There are a few reasons testing is very important when it comes to a growing |
| 33 | +codebase. You should not imagine the situation where you are working on a |
| 34 | +project with one or two people, but a situation where you are working with a |
| 35 | +larger team and with a codebase that the company will use even long after you leave. You |
| 36 | +may not be at the company five years later, or you may at times forget what the code does |
| 37 | +in six months. This is where tests come in to make developers' lives easier as it mainly helps to catch bugs in time and hold us accountable towards high quality error-free code. |
| 38 | + |
| 39 | +### Correctness |
| 40 | +Most obviously, a test is used to verify the correctness of the code. If you |
| 41 | +have ever changed your code then had to test three or more cases manually, then |
| 42 | +you are familiar with the fact that it is quite cumbersome to repeatedly check |
| 43 | +manually. Not only that, it's very easy to forget to check some case when a |
| 44 | +human is doing it by hand. |
| 45 | + |
| 46 | +In contrast, when you write a test, you simply need to run a command in order to |
| 47 | +initiate the tests again, rather than repeating some steps to ensure that your |
| 48 | +code is working. |
| 49 | + |
| 50 | +If you work at a company with a practice of code reviews, consider the perspective of the |
| 51 | +person reviewing your code: How do they know your code doesn't have bugs? How do |
| 52 | +they know it works correctly? If your code is submitted along with tests, the |
| 53 | +reviewer can be aware of exactly what you have or haven't verified about your |
| 54 | +code. |
| 55 | + |
| 56 | +### Ease of change |
| 57 | +Have you ever felt scared to change code, because you weren't sure if it would still work for all the cases after you changed it? With a good test suite, this fear generally |
| 58 | +doesn't exist. Even if the code is rewritten but the same tests pass, indicating |
| 59 | +that the new code has the same behavior, one can feel a lot more secure about |
| 60 | +rewriting the code. |
| 61 | + |
| 62 | +Having good tests allows code to be changed in a more robust fashion. When the |
| 63 | +same tests pass, a developer can be more sure (perhaps not completely sure, |
| 64 | +depending on the tests) that changing the code did not break anything. |
| 65 | +Additionally, it allows people who are not familiar with the code (say, your |
| 66 | +teammates who work on related code, or someone who is responsible for your code |
| 67 | +five years later) to more easily work with the code. |
| 68 | + |
| 69 | +### Documentation |
| 70 | +A well-written test suite serves as documentation. Again, imagine you have just |
| 71 | +joined a company, and you don't know what a function or file does. In fact, if you want to understand what a piece of code does, it's often more productive to go read the |
| 72 | +tests first, rather than the code itself. You must have done this while working on your assignments from previous modules. |
| 73 | + |
| 74 | +In the next section, we'll look at an example of a test, which will help illustrate how the tests themselves can be used to document the code. |
| 75 | + |
| 76 | +## Example code |
| 77 | + |
| 78 | +Let's now take a look at some example code for tests. Even if you don't know much about testing frameworks, you'll find that tests are actually quite readable anyway. |
| 79 | + |
| 80 | +Let's take a look at this example from [Jest](https://jestjs.io), one of the most popular testing frameworks in JavaScript. Most testing frameworks work in approximately the same fashion, simply using different syntax. |
| 81 | + |
| 82 | +```js |
| 83 | +test('adds 1 + 2 to equal 3', () => { |
| 84 | + expect(sum(1, 2)).toBe(3); |
| 85 | + }); |
| 86 | +``` |
| 87 | + |
| 88 | +What does this test do? -- To start off, consider what a function called `sum` |
| 89 | +should do. Even though we can't see the implementation, this is an example of |
| 90 | +how simply reading the test can tell you how the function should behave. |
| 91 | + |
| 92 | +In this test, when the sum function is given the arguments `sum(1, 2)`, we call |
| 93 | +a function `expect` and assert the result `toBe` `3`. Even above that, there is |
| 94 | +a descriptive string (anything can be written there), that tells us that the test checks for `adds 1 + 2 to equal 3`. Again, even though we have no idea how sum is written internally (although in this case, writing such a function should be quite trivial), **only from reading the test**, the behavior of the function is documented in some fashion. |
| 95 | + |
| 96 | +Let's continue reading some tests, without even looking at the implementation of the tested functions for illustrative purposes. |
| 97 | + |
| 98 | +In this example, let's look at the function `absolute`. You may be able to guess |
| 99 | +what the function does from the name, but if not, read the code below, and try |
| 100 | +to figure out what it does. |
| 101 | + |
| 102 | +```js |
| 103 | +describe('absolute', () => { |
| 104 | + it('should return positive number if input is positive', () => { |
| 105 | + const result = absolute(1); |
| 106 | + expect(result).toBe(1); |
| 107 | + }); |
| 108 | + it('should return positive number if input is negative', () => { |
| 109 | + const result = absolute(-1); |
| 110 | + expect(result).toBe(1); |
| 111 | + }); |
| 112 | + it('should return zero if input is zero', () => { |
| 113 | + const result = absolute(0); |
| 114 | + expect(result).toBe(0); |
| 115 | + }); |
| 116 | +}); |
| 117 | +``` |
| 118 | + |
| 119 | +In this example, the `describe` function is used to group together a related set |
| 120 | +of tests. Note how the code almost reads like a written description of the |
| 121 | +behavior of the test. |
| 122 | + |
| 123 | +Finally, let's read one more example of a slightly more complex test. Let's look at a pice of code from the tests of the Express.js Meme API assignment. Hope you haven't forgotten it yet! Even if you have or if you don't understand the specific syntax or function calls, the important part is to try to read the test and see how it helps us understand the behavior of the functionality being tested. |
| 124 | + |
| 125 | +```js |
| 126 | +describe("GET /memes/filter", () => { |
| 127 | + it("responds with empty array for non-matching genre", (done) => { |
| 128 | + const genre = "random"; |
| 129 | + const expectedOutput = []; |
| 130 | + request(app) |
| 131 | + .get("/memes/filter?genre=" + genre) |
| 132 | + .set("Accept", "application/json") |
| 133 | + .expect("Content-Type", /json/) |
| 134 | + .expect(200, (err, res) => { |
| 135 | + if (err) return done(err); |
| 136 | + expect(res.body).to.be.an("array"); |
| 137 | + expect(res.body).to.deep.equal(expectedOutput); |
| 138 | + done(); |
| 139 | + }); |
| 140 | + }); |
| 141 | + |
| 142 | + it("responds with error message when invalid parameter is passed", (done) => { |
| 143 | + const genre = ""; |
| 144 | + const expectedOutput = "invalid query parameter"; |
| 145 | + request(app) |
| 146 | + .get("/memes/filter?genre=" + genre) |
| 147 | + .set("Accept", "application/json") |
| 148 | + .expect("Content-Type", /json/) |
| 149 | + .expect(400, (err, res) => { |
| 150 | + if (err) return done(err); |
| 151 | + expect(res.body).to.equal(expectedOutput); |
| 152 | + done(); |
| 153 | + }); |
| 154 | + }); |
| 155 | +}); |
| 156 | +``` |
| 157 | + |
| 158 | +Try to answer the following questions about the above example: |
| 159 | +* Which piece of functionality is being tested here? |
| 160 | +* How many scenarios are being tested? |
| 161 | +* What is the expected output in each scenario? |
| 162 | + |
| 163 | +By reading the tests in this section, you should have a more concrete understanding of what tests may look like, how they verify correctness, and how they help others understand the behavior of a function. In the next lesson, we will understand a little more about the philosophy and mindset of testing. |
0 commit comments