Learnings
- Generic builder pattern in Java 8 – Tutorials (wordpress.com)
- Template Method Design Pattern in Java | DigitalOcean
- Define variables - Azure Pipelines | Microsoft Learn
Patterns
Toolbox with solutions to solving common design problems, like how to construct objects, structure your components, implement logis.. Software Design Patterns Tutorial - GeeksforGeeks
- Strategy pattern - We define multiple algorithms and let client applications pass the algorithm to be used as a parameter.
- Observer design pattern - Object that watches the state of another Object is called observer, and the Object that is being watched is called subject.
- Template method pattern - The template method defines the steps to execute an algorithm, and it can provide a default implementation that might be common for all or some of the subclasses.
- Chain of responsibility pattern - where a request from the client is passed to a chain of objects to process them. Then the object in the chain will decide who will be processing the request and whether the request is required to be sent to the next object in the chain or not.
Structural patterns
- Flyweight - Reduce memory footprint by keeping references of objects in hashmap, like java string constant pool
- proxy - placeholder that provides controlled access to an object, like additional layer of security or logging
- Façade - hides away the complexity of the underlying system, by providing a simplified view.
- Bridge - The bridge pattern allows the Abstraction and the Implementation to be developed independently, by encapsulating an implementation class (the bridge) inside of an interface class. is an application of the old advice, "prefer composition over inheritance"
- Adapter - This pattern involves a single class, known as the adapter, which is responsible for joining functionalities of independent or incompatible interfaces.
- Decorator - allows behavior to be added to individual objects, dynamically by putting a façade/wrapper on top of it.
- Composite - The client uses the component class interface to interact with objects in the composition structure.
Creational patterns
- Factory - encapsulating creation logic in separate static method, complex objects...
- Builder - construct a complex object step by step. allowing the same construction process to create different representations.
- Singleton - single object creation logging, driver objects, caching, and thread pool, database connections
- Prototype - save object creation by copying existing one, cloning, since object creation is heave process.
SOLID
- Single Responsibility Principle - The more responsibilities your class has, the more often you need to change it. You need to change your class as soon as one of its responsibilities changes.
- Open/Closed Principle - requires software components to be open for extension, but closed for modification. You can achieve that by introducing interfaces for which you can provide different implementations.
- Liskov Substitution Principle - objects of a superclass shall be replaceable with objects of its subclasses without breaking the application. Child classes may extend the behavior but never narrow down behavior.
- Interface Segregation Principle - Clients should not be forced to depend upon interfaces that they do not use.
- Dependency Inversion Principle - high-level and low-level modules should depend on abstractions. Does not change the direction of the dependency as the name is suggesting. It splits the dependency between the high-level and low-level modules by introducing an abstraction between them. So in the end, you get two dependencies.
Unit Tests Red, Green, Refactor
- Red — think about what you want to develop
- Green — think about how to make your tests pass
- Refactor — think about how to improve your existing implementation
The red phase is always the starting point of the red, green, refactor cycle. The purpose of this phase is to write a test that informs the implementation of a feature. Give that method a proper comprehensive Gherkin style name, that explains your intention, starting condition, functionality under test, and finally the outcome. The green phase is where you implement code to make your test pass. The goal is to find a solution, without worrying about optimizing your implementation. In the refactor phase, you are still “in the green.” You can begin thinking about how to implement your code better or more efficiently.
Unit tests that make sense
All about detecting bugs before slipping through to production
Unit tests are only valuable if you're are covering all preconditions (GIVEN) vs expected results (THEN...AND). I always try to formulating my test method names Gherkin style. This forces you to a way of thinking about what your functionality should be accomplishing under every thinkable scenario. I experienced too many units tests that are meaningless, sole reason for their existence is to satisfying test coverage numbers, pure nonsense sitting in the way.
Scenario: Scenario 1
Given preconditions
When actions
Then results
Alike ...
@Test public void givenDefaultMethod_whenCallRealMethod_thenNoExceptionIsRaised()
Like the baeldung always demonstrates
Unit Tests FIRST principle
Verifying that a known fixed input produces a known fixed output. But first step back. What is a unit in general? A unit is normally a method, constructor or deconstructor. Comprehensibility: structural characteristics of software that may indicate a code or design problem that makes software hard to evolve and maintain (compre-hensibility and maintainability).
How much should you unit test? Be careful not to spend too much effort trying to achieve 100% coverage – it may not even be possible or feasible, and really the quality of your tests is the important thing.
- FIRST-Principle (Fast, Independent, Repeatable, Self-Checking and Timely)
- How to write Gherkin tests (Gherkin steps....)
Consumer-Driven Contract
Consumer-driven contract (CDD) is an approach where the consumer drives the changes in the API of the producer. Consumer-driven contract testing is an approach to formalize above mentioned expectations into a contract between each consumer-provider pair. Once the contract is established between Provider and Consumer, this ensures that the contract will not break suddenly.
- https://spring.io/projects/spring-cloud-contract
- https://dzone.com/articles/consumer-driven-contract-testing-with-spring-cloud-contract
Junit5 Extension Model
This custom extension provides a way for Java programmers to create and execute stories and behaviors i.e. BDD specification tests.
- https://www.infoq.com/articles/deep-dive-junit5-extensions/
- https://www.vogella.com/tutorials/JUnit5Extensions/article.html
SpringBoot Controller testing (slices, load only a partial contexts)
There are different ways to test your Controller (Web or API Layer) classes in Spring Boot, some provide support to write pure Unit Tests and some others are more useful for Integration Tests.
- https://thepracticaldeveloper.com/guide-spring-boot-controller-tests/#mockmvc-and-webmvctest-code-example
- Samples from spring framework
Hamcrest and AssertJ
AssertJ provides a rich set of assertions, truly helpful error messages, improves test code readability and is designed to be super easy to use within your favorite IDE.
- AssertJ - fluent assertions java library
- JUnit 5 Tutorial: Writing Assertions With AssertJ
- Hamcrest Tutorial
- Hamcrest at Baeldung
But first about MockMVC
In the past, integration tests were the only meaningful way to test a Spring REST endpoint. This involved spinning up a container like Tomcat or Jetty, deploying the application, calling the endpoint, running some assertions, and then stopping the container. While this is an effective way to test an endpoint, it isn't particularly fast. We're forced to wait while the entire application is stood up, just to test a single endpoint.
An alternative approach is to write vanilla unit tests for each REST controller, manually instantiating the Controller and mocking out any dependencies. These tests will run much faster than integration tests, but they're of limited value. The problem is, by manually creating the Controller outside of the Spring Application Context, the controller loses all the useful request/response handling that Spring takes care of on our behalf. Things like:
- request routing/URL mapping
- request deserialization
- response serialization
- exception translation
What we'd really like is the best of both worlds. The ability to test a fully functional REST controller but without the overhead of deploying the app to a container. Thankfully, that's exactly what MockMvc allows you to do. It stands up a Dispatcher Servlet and all required MVC components, allowing you to test an endpoint in a proper web environment, but without the overhead of running a container.
- REST Endpoint Testing With MockMvc
- The GitHub on provious blog
- MockMvc – Spring MVC testing framework introduction: Testing Spring endpoints
- The GitHub on previous blog
- Unit Test Spring MVC Rest Service: MockMVC, JUnit, Mockito
- Using Cucumber to test Spring MVC controllers
- ucumber + Spring MVC Test: Multiple step definitions entities with a shared context
- The full Github from above
About BDD
(write executable specifications and automated tests that read like documentation)
Cucumber is a testing framework that helps to bridge the gap between software developers and business managers. Tests are written in plain language based on the behavior-driven development (BDD) style of Given, When, Then which any layperson can understand. Cucumber allows software development teams describe how software should behave in plain text. The text is written in a business-readable domain-specific language and serves as documentation, automated tests and development-aid - all rolled into one format.
- If you say you're agile but you aren't using BDD for app testing, you're contradicting yourself.
- An essential guide to agile testing with BDD inside Jira
TDD vs BDD – What’s the Difference Between TDD and BDD?
(TDD is a development practice while BDD is a team methodology.)
In TDD (Test Driven Development), the test is written to check the implementation of functionality, but as the code evolves, tests can give false results. BDD (Behavior Driven Development) is also a test-first approach, but differs by testing the actual behavior of the system from the end users perspective.
In both TDD and BDD approaches, tests are written upfront before the actual code is written. And in both cases, the tests can be used as part of an automated testing framework to minimizing bugs reaching production and ensuring that software can be continuously released without issue.
BDD involves product managers, developers, and test engineers who collaborate to come up with concrete examples of desirable functionality. There is a high level of communication before any implementation. By comparison, TDD can be done by a solo developer without any external input from product managers or stakeholders.
It’s important to note that BDD and TDD aren’t mutually exclusive — many Agile teams use TDD without using BDD. However, BDD ensures that most use cases of the application work on a higher level and provide a greater level of confidence.
The Behavior-Driven Three Amigos
“The Three Amigos” refers to a meeting of the minds of the three primary roles involved in producing software:
- Business – Often named the “business analyst” (BA) or “product owner” (PO), the business role provides what problem must be solved. They provide requirements for the solution. Typically, the business role is non-technical.
- Development – The developer role provides how the solution to the problem will be implemented. They build the software and must be very technical.
- Testing – The testing role, sometimes named “quality assurance” (QA), verifies that the delivered software product works correctly. They also try to find defects. The tester role must be somewhat technical.
Ideally, when The Three Amigos meet during grooming and planning, they would formalize acceptance criteria as Gherkin features.
A great technique for Three Amigos collaboration is Example Mapping – it efficiently identifies rules for acceptance criteria, behavior examples, and open questions. Examples can easily be turned into Gherkin scenarios either during or after the meeting.
- Example Mapping: Getting the Most from Cucumber
- Introducing Example Mapping
- Your first Example Mapping session
- The Behavior-Driven Three Amigos
- BDD 101: Behavior-Driven Agile
Cucumber and BDD
When we do Behaviour-Driven Development with Cucumber we use concrete examples to specify what we want the software to do. Scenarios are written before production code. They start their life as an executable specification. As the production code emerges, scenarios take on a role as living documentation and automated tests.
Validating executable business specifications against your code, follows the BDD (behavior-driven development) methodology. Its intent is to enable developers to write high-level use cases in plain text that can be verified by non-technical stakeholders, and turn them into executable tests, written in a language called Gherkin. Cucumber reads executable specifications written in Plain Text and validates that your application behaves as what is mentioned in the specification.
Gherkin documents are stored in . feature text files and are typically versioned in source control alongside the software.
The Value at the Intersection of TDD, DDD, and BDD
After reading the new
The What, Why, and How of Hybrid Cloud Strategy
Main ingredients Cherkin scenario and steps:
- Scenario: describing one individual test to validate one capability (feature)
- Given: precondition, to put the system in a well define state before the feature starts
- When: event that is exposed to your application, like user action or event triggered by another system
- Then: the expected outcome
- But and And: expression to split out to more specific steps
The specification consists of multiple examples or scenarios. For example:
Feature: Bag Functionality
Scenario: Putting one thing in the bag
- Intellij integration
- Trouble getting Cucumber working with JUnit5 read more here
- Cucumber and JUnit5 at medium (GOOD READ)
- https://www.tutorialspoint.com/cucumber/cucumber_scenario_outline.htm
- https://javapointers.com/automation/cucumber/cucumber-scenario-outline-example/
- About Cucumber
- Spring integration
- Spring Boot Integration Test With Cucumber and Jenkins Pipeline
- This is the Github that goes with above
- Spring Boot REST Service Integration Testing Using Cucumber
- This is the Github that goes with above
- About Cherkin
- REST API Testing with Cucumber
- 10 minute tutorial
- Import to read about the project structure
- Quick intro
Cucumber for Jira
If you are a BDD enthusiast, you’ll be writing executable specifications and automated tests that read like documentation. This documentation is always up to date, because tests are executed by the Continuous Integration (CI) server. Rather than locking away your Gherkin feature files in your Git repository, Cucumber for Jira enables you to share this documentation with your entire team through Jira. Cucumber for Jira integrates with GitHub, GitLab, and Bitbucket (Cloud version).
- The Cucumber for Jira app accelerates your BDD adoption and aligns your development team and Business analysts by enabling BDD in the Jira cloud.
- Quick start
Example Mapping
Before you pull a user story into development, it’s crucial to have a conversation to clarify and confirm the acceptance criteria.
Example Mapping is a method designed to make this conversation short and very productive.
Mockito Verify closer look at
- Mockito: 4 Ways to Verify Interactions
- Mockito Verify Cookbook
- https://www.journaldev.com/21855/mockito-verify
- https://www.baeldung.com/mockito-argumentcaptor
- https://www.baeldung.com/spring-reflection-test-utils
Springboot MockBean and SpyBean
- https://www.concretepage.com/spring-5/spybean-example-spring-test
- https://www.logicbig.com/tutorials/spring-framework/spring-boot/testing-with-spy-bean.html
- https://reflectoring.io/unit-testing-spring-boot/
Testing Kafka and Spring Boot
- https://www.baeldung.com/spring-boot-kafka-testing
- https://blog.mimacom.com/testing-apache-kafka-with-spring-boot-junit5/
- https://medium.com/trendyol-tech/how-to-integration-test-on-spring-kafka-producer-cb9d1caf0795
- https://www.confluent.io/blog/advanced-testing-techniques-for-spring-kafka/
- https://kreuzwerker.de/en/post/testing-a-kafka-consumer-with-avro-schema-messages-in-your-spring-boot
- https://medium.com/@igorvlahek1/no-need-for-schema-registry-in-your-spring-kafka-tests-a5b81468a0e1
Junit5 and TestContainers
- https://www.testcontainers.org/test_framework_integration/junit_5/
- https://karuppiah7890.github.io/blog/posts/testcontainers-part-1-an-introduction-to-a-new-way-of-integration-testing/
- https://www.testcontainers.org/quickstart/junit_5_quickstart/
- https://www.baeldung.com/spring-boot-testcontainers-integration-test
- https://fullstackcode.dev/2021/05/16/springboot-integration-testing-with-testcontainers/
- Junit 5 testcontainers and kafka
- https://dev.to/rieckpil/write-spring-boot-integration-tests-with-testcontainers-junit-4-5-40am
- SpringBoot @DataJpaTest is throwing Failed to load ApplicationContext exception
- How to populate data in testcontainers?
- Kafkacontainers test example
- https://github.com/jupiter-tools/spring-test-kafka
- Example from above
- Best TestContainer post with postgreSQL and Flyway
The rules are the same but there is a slight difference. @DataJpaTest is annotated with @AutoConfigureTestDatabase itself. This annotation replaces any data source with the H2 instance by default. So, we need to override this behavior by adding replace=Replace.NONE property.