Test-driven development with Java create higher-quality software by writing tests first with solid and hexagonal architecture
Drive development with automated tests and gain the confidence you need to write high-quality software Key Features Get up and running with common design patterns and TDD best practices Learn to apply the rhythms of TDD - arrange, act, assert and red, green, refactor Understand the challenges of imp...
Otros Autores: | |
---|---|
Formato: | Libro electrónico |
Idioma: | Inglés |
Publicado: |
Birmingham, England :
Packt Publishing, Limited
[2023]
|
Edición: | 1st ed |
Materias: | |
Ver en Biblioteca Universitat Ramon Llull: | https://discovery.url.edu/permalink/34CSUC_URL/1im36ta/alma991009714839106719 |
Tabla de Contenidos:
- Cover
- Title Page
- Copyright and Credit
- Dedicated
- Contributors
- Table of Contents
- Preface
- Part 1: How We Got to TDD
- Chapter 1: Building the Case for TDD
- Writing code badly
- Understanding why bad code is written
- Recognizing bad code
- Bad variable names
- Bad function, method, and class names
- Error-prone constructs
- Coupling and cohesion
- Decreasing team performance
- Diminishing business outcomes
- Summary
- Questions and answers
- Further reading
- Chapter 2: Using TDD to Create Good Code
- Designing good quality code
- Say what you mean, mean what you say
- Take care of the details in private
- Avoid accidental complexity
- Revealing design flaws
- Analyzing the benefits of writing tests before production code
- Preventing logic flaws
- Protecting against future defects
- Documenting our code
- Summary
- Questions and answers
- Further reading
- Chapter 3: Dispelling Common Myths about TDD
- Writing tests slows me down
- Understanding the benefits of slowing down
- Overcoming objections to tests slowing us down
- Tests cannot prevent every bug
- Understanding why people say tests cannot catch every bug
- Overcoming objections to not catching every bug
- How do you know the tests are right?
- Understanding the concerns behind writing broken tests
- Providing reassurance that we test our tests
- TDD guarantees good code
- Understanding problem-inflated expectations
- Managing your expectations of TDD
- Our code is too complex to test
- Understanding the causes of untestable code
- Reframing the relationship between good design and simple tests
- Managing legacy code without tests
- I don't know what to test until I write the code
- Understanding the difficulty of starting with testing
- Overcoming the need to write production code first
- Summary.
- Questions and answers
- Further reading
- Part 2: TDD Techniques
- Chapter 4: Building an Application Using TDD
- Technical requirements
- Preparing our development environment
- Installing the IntelliJ IDE
- Setting up the Java project and libraries
- Introducing the Wordz application
- Describing the rules of Wordz
- Exploring agile methods
- Reading user stories - the building block of planning
- Combining agile development with TDD
- Summary
- Questions and answers
- Further reading
- Chapter 5: Writing Our First Test
- Technical requirements
- Starting TDD: Arrange-Act-Assert
- Defining the test structure
- Working backward from outcomes
- Increasing workflow efficiency
- Defining a good test
- Applying the FIRST principles
- Using one assert per test
- Deciding on the scope of a unit test
- Catching common errors
- Asserting exceptions
- Only testing public methods
- Preserving encapsulation
- Learning from our tests
- A messy Arrange step
- A messy Act step
- A messy Assert step
- Limitations of unit tests
- Code coverage - an often-meaningless metric
- Writing the wrong tests
- Beginning Wordz
- Summary
- Questions and answers
- Chapter 6: Following the Rhythms of TDD
- Technical requirements
- Following the RGR cycle
- Starting on red
- Keep it simple - moving to green
- Refactoring to clean code
- Writing our next tests for Wordz
- Summary
- Questions and answers
- Further reading
- Chapter 7: Driving Design - TDD and SOLID
- Technical requirements
- Test guide - we drive the design
- SRP - simple building blocks
- Too many responsibilities make code harder to work with
- Ability to reuse code
- Simplified future maintenance
- Counter-example - shapes code that violates SRP
- Applying SRP to simplify future maintenance
- Organizing tests to have a single responsibility.
- DIP - hiding irrelevant details
- Applying DI to the shapes code
- LSP - swappable objects
- Reviewing LSP usage in the shapes code
- OCP - extensible design
- Adding a new type of shape
- ISP - effective interfaces
- Reviewing ISP usage in the shapes code
- Summary
- Questions and answers
- Chapter 8: Test Doubles - Stubs and Mocks
- Technical requirements
- The problems collaborators present for testing
- The challenges of testing unrepeatable behavior
- The challenges of testing error handling
- Understanding why these collaborations are challenging
- The purpose of test doubles
- Making the production version of the code
- Using stubs for pre-canned results
- When to use stub objects
- Using mocks to verify interactions
- Understanding when test doubles are appropriate
- Avoiding the overuse of mock objects
- Don't mock code you don't own
- Don't mock value objects
- You can't mock without dependency injection
- Don't test the mock
- When to use mock objects
- Working with Mockito - a popular mocking library
- Getting started with Mockito
- Writing a stub with Mockito
- Writing a mock with Mockito
- Blurring the distinction between stubs and mocks
- Argument matchers - customizing behavior of test doubles
- Driving error handling code with tests
- Testing an error condition in Wordz
- Summary
- Questions and answers
- Further reading
- Chapter 9: Hexagonal Architecture -Decoupling External Systems
- Technical requirements
- Why external systems are difficult
- Environmental problems bring trouble
- Accidentally triggering real transactions from tests
- What data should we expect?
- Operating system calls and system time
- Challenges with third-party services
- Dependency inversion to the rescue
- Generalizing this approach to the hexagonal architecture.
- Overview of the hexagonal architecture's components
- The golden rule - the domain never connects directly to adapters
- Why the hexagon shape?
- Abstracting out the external system
- Deciding what our domain model needs
- Writing the domain code
- Deciding what should be in our domain model
- Using libraries and frameworks in the domain model
- Deciding on a programming approach
- Substituting test doubles for external systems
- Replacing the adapters with test doubles
- Unit testing bigger units
- Unit testing entire user stories
- Wordz - abstracting the database
- Designing the repository interface
- Designing the database and random numbers adapters
- Summary
- Questions and answers
- Further reading
- Chapter 10: FIRST Tests and the Test Pyramid
- Technical requirements
- The test pyramid
- Unit tests - FIRST tests
- Integration tests
- What should an integration test cover?
- Testing database adapters
- Testing web services
- Consumer-driven contract testing
- End-to-end and user acceptance tests
- Acceptance testing tools
- CI/CD pipelines and test environments
- What is a CI/CD pipeline?
- Why do we need continuous integration?
- Why do we need continuous delivery?
- Continuous delivery or continuous deployment?
- Practical CI/CD pipelines
- Test environments
- Testing in production
- Wordz - integration test for our database
- Fetching a word from the database
- Summary
- Questions and answers
- Further reading
- Chapter 11: Exploring TDD with Quality Assurance
- TDD - its place in the bigger quality picture
- Understanding the limits of TDD
- No more need for manual testing?
- Manual exploratory - discovering the unexpected
- Code review and ensemble programming
- User interface and user experience testing
- Testing the user interface
- Evaluating the user experience.
- Security testing and operations monitoring
- Incorporating manual elements into CI/CD workflows
- Summary
- Questions and answers
- Further reading
- Chapter 12: Test First, Test Later, Test Never
- Adding tests first
- Test-first is a design tool
- Tests form executable specifications
- Test-first provides meaningful code coverage metrics
- Beware of making a code coverage metric a target
- Beware of writing all tests upfront
- Writing tests first helps with continuous delivery
- We can always test it later, right?
- Test-later is easier for a beginner to TDD
- Test-later makes it harder to test every code path
- Test-later makes it harder to influence the software design
- Test-later may never happen
- Tests? They're for people who can't write code!
- What happens if we do not test during development?
- Testing from the inside out
- Testing from the outside in
- Defining test boundaries with hexagonal architecture
- Inside-out works well with the domain model
- Outside-in works well with adapters
- User stories can be tested across the domain model
- Summary
- Questions and answers
- Further reading
- Part 3: Real-World TDD
- Chapter 13: Driving the Domain Layer
- Technical requirements
- Starting a new game
- Test-driving starting a new game
- Tracking the progress of the game
- Triangulating word selection
- Playing the game
- Designing the scoring interface
- Triangulating game progress tracking
- Ending the game
- Responding to a correct guess
- Triangulating the game over due to too many incorrect guesses
- Triangulating response to guess after game over
- Reviewing our design
- Summary
- Questions and answers
- Further reading
- Chapter 14: Driving the Database Layer
- Technical requirements
- Installing the Postgres database
- Creating a database integration test.
- Creating a database test with DBRider.