{"id":14,"date":"2019-06-17T09:54:24","date_gmt":"2019-06-17T09:54:24","guid":{"rendered":"https:\/\/www.bddtesting.com\/?page_id=14"},"modified":"2019-06-17T10:18:00","modified_gmt":"2019-06-17T10:18:00","slug":"tdd-testing-vs-bdd-testing","status":"publish","type":"page","link":"https:\/\/www.bddtesting.com\/tdd-testing-vs-bdd-testing\/","title":{"rendered":"TDD testing vs BDD testing"},"content":{"rendered":"\n
Unit testing<\/h3>\n\n\n\n
A unit test focuses on a single \u201cunit of code\u201d \u2013 usually a function in an object or module. By making the test specific to a single function, the test should be simple, quick to write, and quick to run. This means you can have many unit tests, and more unit tests means more bugs caught. They are especially helpful if you need to change your code: When you have a set of unit tests verifying your code works, you can safely change the code and trust that other parts of your program will not break.<\/p>\n\n\n\n
A unit test should be isolated from dependencies \u2013 for example, no network access and no database access. There are tools that can replace these dependencies with fakes you can control. This makes it trivial to test all kinds of scenarios that would otherwise require a lot of setup. For example, imagine having to set up an entire database just to run a test. Ugh, no thanks.<\/p>\n\n\n\n
There is a misconception that unit tests require a specific syntax to write. This so-called \u201cxUnit style\u201d syntax is common in many slightly older testing tools. Below is an example of the \u201cxUnit style\u201d, using Mocha:<\/p>\n\n\n\n
suite(‘My test suite name’, function<\/strong>() {\n setup(function<\/strong>() {\n \/\/do setup before tests<\/em>\n });\n \n teardown(function<\/strong>() {\n \/\/clean up after tests<\/em>\n });\n \n test(‘x should do y’, function<\/strong>() {\n \/\/test something<\/em>\n });\n});<\/td><\/tr><\/tbody><\/table>\n\n\n\n
But this is just an example of what a tool looks like. You don\u2019t have to use any specific syntax for unit tests \u2013 in fact, you can even write unit tests with plain JavaScript:<\/p>\n\n\n\n
\/\/suite: User<\/em>\n \n\/\/test: Name should start empty<\/em>\nvar<\/strong> user = new<\/strong> User();\nif<\/strong>(user.getName() !== ”) {\n throw<\/strong> new<\/strong> Error(‘User name should start as empty’);\n}\n \n\/\/test: Password should be hashed<\/em>\nvar<\/strong> user = new<\/strong> user();\nuser.setPassword(‘hello’);\nif<\/strong>(user.getPassword() != bcrypt(‘hello’)) {\n throw<\/strong> new<\/strong> Error(‘User password should be hashed with bcrypt’);\n}<\/td><\/tr><\/tbody><\/table>\n\n\n\n
The basic pieces of a unit test are there: Individual tests, which test one thing, and they are isolated from each other. You could use scripts like this to build rudimentary unit tests for your code. But using an actual unit testing tool such as Mocha or Jasmine will make it easier to write tests, and they have other helpful features such as better reporting when tests fail (which makes it easier to find out what went wrong)<\/p>\n\n\n\n
Some think that any automated test is a unit test. This is not true. There are different types of automated tests, and each type has its own purpose.<\/p>\n\n\n\n
Here are three of the most common types of automated tests:<\/p>\n\n\n\n
Unit tests<\/strong>: A single piece of code (usually an object or a function) is tested, isolated from other pieces<\/li>
Integration tests<\/strong>: Multiple pieces are tested together, for example testing database access code against a test database<\/li>
Acceptance tests (also called Functional tests)<\/strong>: Automatic testing of the entire application, for example using a tool like Selenium to automatically run a browser.<\/li><\/ul>\n\n\n\n
If you feel it\u2019s not easy to write a unit test, chances are it\u2019s not a unit test at all. Both integration tests and acceptance tests are more complex and usually run slower. They are also more difficult to maintain than unit tests, so if you\u2019re having problems, make sure you\u2019re writing the right kind of test.<\/p>\n\n\n\n
TDD<\/h3>\n\n\n\n
TDD or Test-Driven Development is a process for when you write and run your tests. Following it makes it possible to have a very high test-coverage. Test-coverage refers to the percentage of your code that is tested automatically, so a higher number is better. TDD also reduces the likelihood of having bugs in your tests, which can otherwise be difficult to track down.<\/p>\n\n\n\n
The TDD process consists of the following steps:<\/p>\n\n\n\n
Start by writing a test<\/li>
Run the test and any other tests. At this point, your newly added test should fail. If it doesn\u2019t fail here, it might not be testing the right thing and thus has a bug in it.<\/li>
Write the minimum amount of code required to make the test pass<\/li>
Run the tests to check the new test passes<\/li>
Optionally refactor your code<\/li>
Repeat from 1<\/li><\/ol>\n\n\n\n
It can take some effort to learn well, but spending the time can pay off big. TDD projects often get a code-coverage of 90-100%, which means maintaining the code and adding new features is easy. This is because you have a large set of tests, so you can trust your code and changes work, and didn\u2019t break any other code either.<\/p>\n\n\n\n
Some think you must use the \u201cxUnit style\u201d testing tools to use the TDD process. This is not the case \u2013 TDD works great with unit tests, but you can apply it to other testing methods as well. It also does not require any specific tool or syntax.<\/p>\n\n\n\n
This is a unit test of an imaginary counter object. We test that after calling tick, the value should be 1, which sounds like it makes sense. But there\u2019s a problem in the test. The test is completely dependent on the fact that the counter starts at 0. So in other words, this test is relying on two things.<\/p>\n\n\n\n
Counter starts at 0<\/li>
Ticking increments by 1<\/li><\/ol>\n\n\n\n
The fact the counter starts at 0 is an implementation detail that\u2019s irrelevant to the behavior of the tick() function. Therefore it should not have any bearing on the test. The only reason we wrote the test like this is because we were thinking of the implementation, not of the behavior.<\/p>\n\n\n\n
BDD suggests to test behaviors, so instead of thinking of how the code is implemented, we spend a moment thinking of what the scenario is. Typically you phrase BDD tests in the form of \u201cit should do something\u201d. So when ticking a counter, it should increment count by one.<\/p>\n\n\n\n
The important part here is thinking of the scenario, rather than the implementation, can lead you to design a better test.<\/p>\n\n\n\n
In this version of the test, which uses Mocha\u2019s BDD style functions, we removed the implementation detail. Instead of relying on the counter starting at 0, we are comparing against counter.count + 1 which makes much more sense in terms of testing against behavior.<\/p>\n\n\n\n
Sometimes your requirements change. Let\u2019s imagine that for some reason the Counter has to start at some other value. Before, we would have to change the test to accommodate that, but with the BDD-variant there is no need to do so.<\/p>\n\n\n\n