O'Reilly logo

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Practical Test-Driven Development using C# 7

Book Description

Develop applications for the real world with a thorough software testing approach

About This Book

  • Develop a thorough understanding of TDD and how it can help you develop simpler applications with no defects using C# and JavaScript
  • Adapt to the mindset of writing tests before code by incorporating business goals, code manageability, and other factors
  • Make all your software units and modules pass tests by analyzing failed tests and refactoring code as and when required

Who This Book Is For

This book is for software developers with a basic knowledge of Test Driven Development (TDD) who want a thorough understanding of how TDD can benefit them and the applications they produce. The examples in this book are in C#, and you will need a basic understanding of C# to work through these examples.

What You Will Learn

  • The core concepts of TDD
  • Testing in action with a real-world case study in C# and JavaScript using React
  • Writing proper Unit Tests and testable code for your application
  • Using different types of test double such as stubs, spies, and mocks
  • Growing an application guided by tests
  • Exploring new developments on a green-field application
  • Mitigating the problems associated with writing tests for legacy applications
  • Modifying a legacy application to make it testable

In Detail

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!

Style and approach

A practical step-by-step approach with real-world case studies.

Downloading the example code for this book You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the files e-mailed directly to you.

Table of Contents

  1. Preface
    1. Who this book is for
    2. What this book covers
    3. To get the most out of this book
      1. Download the example code files
      2. Download the color images
      3. Conventions used
    4. Get in touch
      1. Reviews
  2. Why TDD is Important
    1. First, a little background
      1. John's story on TDD
      2. Clayton's story on TDD
    2. So, what is TDD?
    3. An approach to TDD 
      1. An alternative approach 
      2. The process
        1. Red, green, and refactor
        2. Coder's block
      3. Why should we care?
    4. Arguments against TDD
      1. Testing takes time
      2. Testing is expensive
      3. Testing is difficult
      4. We don't know how
    5. Arguments in favor of TDD
      1. Reduces the effort of manual testing
      2. Reduces bug count
      3. Ensures some level of correctness
      4. Removes the fear of refactoring
      5. A better architecture 
      6. Faster development 
    6. Different types of test
      1. Unit tests 
      2. Acceptance tests 
      3. Integration tests 
      4. End to end tests 
        1. Quantity of each test type 
      5. Parts of a unit test
        1. Arrange
        2. Act
        3. Assert
      6. Requirements 
        1. Why are they important? 
        2. User stories 
          1. Role 
          2. Request 
          3. Reason 
        3. Gherkin 
          1. Givens 
          2. When 
          3. Then 
      7. Our first tests in C#
        1. Growing the application with tests
      8. Our first tests in JavaScript
    7. Why does it matter?
    8. Summary
  3. Setting Up the .NET Test Environment
    1. Installing the .NET Core SDK
      1. Getting set up with VS Code
        1. Downloading the IDE
        2. Installing the VS Code
        3. Adding extensions
    2. Creating a project in VS Code
      1. Setting up Visual Studio Community
        1. Downloading Visual Studio Community
        2. Installing Visual Studio Community
    3. Switching to xUnit
      1. Code katas
        1. FizzBuzz
      2. Creating the test project
        1. The Given3ThenFizz test
        2. The Given5ThenBuzz test
        3. The Given15ThenFizzBuzz test
        4. The Given1Then1 test
        5. Theories
        6. Solution to the FizzBuzz Problem
    4. What is Speaker Meet?
      1. Web API project
      2. Listing Speakers (API)
        1. Requirements
        2. A new test file
    5. Summary
  4. Setting Up a JavaScript Environment
    1. Node.js
      1. What is Node?
      2. Why do we need Node?
      3. Installing Node
        1. Linux
        2. Mac OSX
        3. Windows
      4. NPM
        1. What is NPM?
        2. Why do we need NPM?
        3. Installing NPM?
    2. A quick introduction to JavaScript IDEs
      1. Visual Studio Code
        1. Why Visual Studio Code?
        2. Installing Visual Studio Code
          1. Linux
          2. Mac
          3. Windows
        3. Installing the plugins you will need
        4. Configuring the testing environment
      2. WebStorm
        1. Why WebStorm?
        2. Installing WebStorm
          1. Linux
          2. Mac
          3. Windows
        3. Installing the plugins you will need
        4. Configuring the testing environment
      3. Create React App
        1. What is Create React App?
        2. Installing the global module
        3. Creating a React application
          1. Running the Create React App script
      4. Mocha and Chai
        1. Jest
        2. Mocha
        3. Chai
        4. Sinon
        5. Enzyme
        6. Ejecting the React app
        7. Configuring to use Mocha and Chai
      5. A quick kata to check our test setup
        1. The requirements
        2. The execution
      6. Starting the kata
    3. Summary
  5. What to Know Before Getting Started
    1. Untestable code
      1. Dependency Injection
        1. Static
        2. Singleton
        3. Global state
      2. Abstracting third-party software
      3. Test doubles
      4. Mocking frameworks
      5. The SOLID principles
        1. The Single Responsibility Principle
        2. The Open/Closed principle
        3. The Liskov Substitution principle
        4. The Interface Segregation principle
        5. The Dependency Inversion principle
      6. Timely greeting
      7. Fragile tests
        1. False positives and false failures
        2. Abstract DateTime
      8. Test double types
        1. Dummies
        2. Dummy logger
          1. Example in C#
          2. Example in JavaScript
        3. Stubs
          1. Example in C#
          2. Example in JavaScript
        4. Spies
          1. Example in C#
          2. Example in JavaScript
        5. Mocks
          1. Example in C#
          2. Example in JavaScript
        6. Fakes
          1. Example in C#
          2. Example in JavaScript
      9. N-Tiered example
        1. Presentation layer
        2. Moq
        3. Business layer
    2. Summary
  6. Tabula Rasa – Approaching an Application with TDD in Mind
    1. Where to begin
    2. Yak shaving
      1. Big design up front
    3. A clean slate
      1. One bite at a time
      2. Minimum Viable Product
      3. Different mindset
      4. YAGNI – you aren't gonna need it
    4. Test small
    5. Devil's advocate
    6. Test negative cases first
    7. When testing is painful
      1. A spike
      2. Assert first
      3. Stay organized
    8. Breaking down Speaker Meet
      1. Speakers
      2. Communities
      3. Conferences
      4. Technical requirements
    9. Summary
  7. Approaching the Problem
    1. Defining the problem
    2. Digesting the problem
      1. Epics, features, and stories; oh my!
        1. Epics
        2. Features
        3. Stories
        4. Maintain your backlog
      2. The Speaker Meet problem
        1. Meaningful separation
          1. Speakers
          2. Communities
          3. Conferences
          4. Separate by team function
          5. Technical separations
        2. Technical requirements
          1. React web user interface
          2. .NET Core
          3. .NET Web API
          4. Entity Framework
          5. Azure
          6. Database
    3. An N-Tiered hexagonal architecture
      1. Hexagonal architecture
      2. Basic yet effective N-Tiered divisions
        1. Service layer
          1. Microservices
        2. Data access layer
          1. Repository Pattern
          2. Generic repository
        3. User interface adapter layer
      3. User interface layer
        1. Front-end business layer
        2. Front-end user interface layer
        3. Front-end data source layer
    4. Testing direction
      1. Back-to-front
        1. Defining a data source
        2. Creating a business layer
        3. Building a user interface
      2. Front-to-back
        1. Defining a user interface
        2. Creating a business layer
        3. Building a data source
      3. Inside out
        1. Defining a business layer
    5. Summary
  8. Test-Driving C# Applications
    1. Reviewing the requirements
    2. Speaker listing
      1. API
      2. API tests
        1. Moq
        2. Testing exception cases
      3. Service
      4. Service tests
      5. Clean tests  
      6. Repository
        1. The IRepository interface
        2. FakeRepository
      7. Using factories with the FakeRepository
        1. Soft delete
    3. Speaker details
      1. API
      2. API tests
      3. Service
      4. Service tests
      5. Clean the tests
      6. More from the repository
      7. Additional factory work
      8. Testing exception cases
    4. Summary
  9. Abstract Away Problems
    1. Abstracting away problems
      1. Gravatar
        1. Starting with an interface
        2. Implementing a test version of the interface
        3. Implementing the production version of the interface
      2. Future planning
    2. Abstracting the data layer
      1. Extending the repository pattern
        1. The Get method
        2. The GetAll method
        3. The Create method
        4. The Delete method
        5. The Update method
      2. Ensuring functionality
        1. Creating a speaker
        2. Getting a single speaker
        3. Getting multiple speakers
        4. Updating a speaker
        5. Deleting a speaker
    3. Genericizing the repository
      1. Step one – abstract interface
      2. Step two – abstract the concrete class
        1. Converting Create to a generic method
        2. Converting Get to a generic method
        3. Converting GetAll to a generic method
        4. Converting Update to a generic method
        5. Converting Delete to a generic method
      3. Step three – reorient the tests to use the generic repository
        1. InMemoryRepository Create tests
        2. InMemoryRepository Get tests
        3. InMemoryRepository GetAll tests
        4. InMemoryRepository Update tests
      4. Entity Framework
        1. DbContext
        2. Models
        3. Generic repository
      5. Dependency Injection
        1. Wire it all up
        2. Postman
    4. Summary
  10. Testing JavaScript Applications
    1. Creating a React app
      1. Ejecting the app
      2. Configuring Mocha, Chai, Enzyme, and Sinon 
    2. The plan
      1. Considering the React component
      2. Looking at Redux testability
        1. The store
        2. Actions
        3. Reducers
      3. Unit-testing an API service
    3. Speaker listing
      1. A mock API service
      2. The Get All Speakers action
        1. Testing a standard action
        2. Testing a thunk
      3. The Get All Speakers reducer
      4. The Speaker listing component
    4. Speaker detail
      1. Adding to the mock API Service
      2. The Get Speaker action
      3. The Get Speaker reducer
      4. The Speaker Detail component
    5. Summary
  11. Exploring Integrations
    1. Implementing a real API service
      1. Replacing the mock API with the real API service
      2. Using Sinon to mock Ajax responses
        1. Fixing existing tests
        2. Mocking the server
      3. Application configuration
    2. End-to-end integration tests
      1. Benefits
      2. Detriments
      3. How much end-to-end testing should you do?
    3. Configuring the API project
      1. Integration test project
      2. Where to begin?
      3. Verifying the repository calls into the DB context
        1. InMemory database
        2. Adding speakers to the InMemory database
      4. Verify that the service calls the DB through the repository
        1. ContextFixture
      5. Verify the API calls into the service
        1. TestServer
        2. ServerFixture
    4. Summary
  12. Changes in Requirements
    1. Hello World
      1. A change in requirements
        1. Good evening 
    2. FizzBuzz
      1. A new feature
        1. Number not found
    3. TODO app  
      1. Mark complete
      2. Adding tests
      3. Production code
        1. But don't remove from the list!
      4. Adding tests
      5. Production code
    4. Changes to Speaker Meet
      1. Changes to the back-end
      2. Changes to the front-end 
        1. Sorted by rating on client side
    5. What now?
      1. Premature optimization
    6. Summary
  13. The Legacy Problem
    1. What is legacy code?
      1. Why does code go bad?
      2. When does a project become legacy?
      3. What can be done to prevent legacy decay?
    2. Typical issues resulting from legacy code
      1. Unintended side effects
        1. Open Closed Principle and legacy code
        2. Liskov Substitution Principle and legacy code
      2. Over-optimization
      3. Overly clever code
      4. Tight coupling to third-party software
    3. Issues that prevent adding tests 
      1. Direct dependence on framework and third-party code 
      2. Law of Demeter
      3. Work in the constructor
      4. Global state
      5. Static methods
      6. Large classes and functions 
    4. Dealing with legacy problems
      1. Safe refactoring
        1. Converting values to variables
        2. Extracting a method
        3. Extracting a class
        4. Abstracting third-party libraries and framework code
      2. Early tests
        1. Gold standard tests
        2. Testing all potential outcomes 
    5. Moving forward 
      1. Fixing bugs 
      2. Free to do unsafe refactoring 
    6. Summary
  14. Unraveling a Mess
    1. Inheriting code
      1. The game
      2. A change is requested
    2. Life sometimes hands you lemons
      1. Getting started
      2. Abstracting a third-party class
      3. Unexpected Input
      4. Making sense of the madness
      5. Final beautification
      6. Ready for enhancements
    3. Summary
  15. A Better Foot Forward
    1. What we've covered
    2. Moving forward
      1. TDD is a personal practice
      2. You don't need permission
      3. Grow applications through tests
    3. Introducing TDD to your team
      1. Don’t force TDD on anyone
      2. Gamification of TDD
      3. Showing your team the benefits
      4. Review the results
    4. Rejoining the world as a TDD expert
      1. Seek a mentor
      2. Becoming a mentor
      3. Practice, practice, practice
    5. Summary
  16. Other Books You May Enjoy
    1. Leave a review - let other readers know what you think