Book Image

Practical Test-Driven Development using C# 7

By : John Callaway, Clayton Hunt
Book Image

Practical Test-Driven Development using C# 7

By: John Callaway, Clayton Hunt

Overview of this book

Test-Driven Development (TDD) is a methodology that helps you to write as little as code as possible to satisfy software requirements, and ensures that what you've written does what it's supposed to do. If you're looking for a practical resource on Test-Driven Development this is the book for you. You've found a practical end-to-end guide that will help you implement Test-Driven Techniques for your software development projects. You will learn from industry standard patterns and practices, and shift from a conventional approach to a modern and efficient software testing approach in C# and JavaScript. This book starts with the basics of TDD and the components of a simple unit test. Then we look at setting up the testing framework so that you can easily run your tests in your development environment. You will then see the importance of defining and testing boundaries, abstracting away third-party code (including the .NET Framework), and working with different types of test double such as spies, mocks, and fakes. Moving on, you will learn how to think like a TDD developer when it comes to application development. Next, you'll focus on writing tests for new/changing requirements and covering newly discovered bugs, along with how to test JavaScript applications and perform integration testing. You’ll also learn how to identify code that is inherently un-testable, and identify some of the major problems with legacy applications that weren’t written with testability in mind. By the end of the book, you’ll have all the TDD skills you'll need and you’ll be able to re-enter the world as a TDD expert!
Table of Contents (21 chapters)
Title Page
Packt Upsell
Foreword
Contributors
Preface
4
What to Know Before Getting Started
Index

Arguments in favor of TDD


What we would like to focus on here are the positives, the arguments in favor of TDD.

Reduces the effort of manual testing

We already mentioned that we, as professionals, will not ship anything without first determining that it works. Throwing something over the wall to QA, to our users, or to the general public and hoping that it all works as expected just isn't how we do business. We will verify that our code and our applications work as expected. In the beginning, while the application is small and has little functionality, we can manually test everything we can think of. But, as the application grows in size and complexity, it just isn't feasible for developers or anyone else to manually test an entire application. It’s too time-consuming and costly to do this manually. We can save ourselves time and our clients and companies money by automating our testing. We can do so quite easily, from the beginning, through TDD.

Reduces bug count

As our application grows, so do our tests. Or shall we say, our test suite has grown, and by making our tests pass, our application has grown. As both have grown, we've covered the happy path (for example: 2 + 2 = 4) as well as potential failures (for example: 2 + banana = exception). If the method or function under test can accept an input parameter, there is a potential for failure. You can reduce the potential for unexpected behavior, bugs, and exceptions by writing code to guard against these scenarios. As you write tests to express potential failures, your production code will inherently become more robust and less prone to errors. If a bug does slip by and make it to QA, or even to a production environment, then it's easy enough to add a new test to cover the newly discovered defect.

The added benefit of approaching bugs in this fashion is that the same bug rarely crops up again at some later date, as the new tests guard against this. If the same bug does appear, you know that, while the same result has happened, the bug occurred in a new and different way. With the addition of another test to cover this new scenario, this will likely be the last time you see the same old bug.

Ensures some level of correctness

With a comprehensive suite of tests, you can demonstrate some level of correctness. At some point, someone somewhere will ask you whether you are done. How will you show that you have added the desired functionality to an application?

Removes the fear of refactoring

Let's face it, we've all worked on legacy applications that we were scared to touch. Imagine if the class you were tasked with modifying were covered by a comprehensive set of unit tests. Picture how easy it would be to make a change and know that all was right with the world because all of the unit tests still passed.

A better architecture 

Writing unit tests tends to push your code towards a decoupled design. Tightly coupled code quickly becomes burdensome to test, and so, to make one's life easier, a Test-Driven Developer will begin to decouple the code. Decoupled code is easier to swap in and out, which means that, instead of modifying a tangled knot of production code, often all that a developer needs to do to make the necessary changes is swap out a subcomponent with a new module of code. 

Faster development 

It may not feel like it at first (in fact, it definitely will not feel like it at first), but writing unit tests is an excellent way to speed up development. Traditionally, a developer receives requirements from the business, sits down, and begins shooting lightning from her fingertips, allowing the code to pour out until an executable application has been written. Before TDD, a developer would write code for a few minutes and then launch the application so that she could see if the code worked or not. When a mistake was found, the developer would fix it and launch the application once again to check whether the fix worked. Often, a developer would find that her fix had broken something else and would then have to chase down what she had broken and write another fix. The process described is likely one that you and every other developer in the world are familiar with. Imagine how much time you have lost fixing bugs that you found while doing developer testing. This does not even include the bugs found by QA or in production by the customer. 

Now, let's picture another scenario. After learning TDD, when we receive requirements from the business, we quickly convert those requirements directly into tests. As each test passes we know that, as per the requirements, our code does exactly what has been asked of it. We might discover some edge cases along the way and create tests to ensure the code has the correct behavior for each one. It would be rare to discover that a test is failing after having made it pass. But, when we do cause a test to fail, we can quickly fix it by using the undo command in our editor. This allows us to hardly even run the application until we are ready to submit our changes to QA and the business. Still, we try to verify that the application behaves as required before submitting, but now we don't do this manually, every few minutes. Instead, let your unit tests verify your code each time you save a file.