How we ended up using BDD
It was not our primary goal to use Behaviour Driven Development (BDD) in the project at a customer, but while finding and optimizing our agile software development process we recognized that we established the building blocks of BDD. It works quite well and offers a lot of space and flexibility for our future plans, switching our architecture to microservices.
The project setup
But let us start at the beginning of the project. We started on a green field project but had to embed in a system context with established interfaces and many third party services as we had to replace a legacy system. Also as a newly formed team consisting of internal and external employees we had to find our team spirit and embed into the existing organizational structure. With at least one dedicated Product Owner (PO) and a dedicated Scrum Master we started as a team of 7 people. We are one of multiple Scrum teams in an organization sector. The operations team is (still) in another sector and the domain experts or Functional Owner (FO) even in another building. On the one hand it makes communication on domain topics harder, on the other hand with this setting we had a lot of liberties to build, release and deploy whenever we want. Noticing that other teams organized their cyclic release as part of their scrum process every two weeks our way to deploy after feature complete, seemed to be unconventional to others.
Trust as prerequisite to keep liberties in development process
As time went by we had our first deployment to production. We have been consuming other services and vice versa. While more features were added, the complexity and the amount of deployments to production increased. Our POs’ confidence in our unconventional release and deploy process decreased, perhaps feeling that the project got out of hand. Of course we sent announcement E-Mails to relevant stakeholders, but somehow we had not built up enough trust yet and our POs still had the desire to make manual tests on the release stage. So we started to create charts of all processes together with our POs as part of our development process just before talking about the user story in our refinement. It was and still is helpful for two reasons. On the one hand it was creating a format the whole team understands as it was simplifying the process and serving as documentation. On the other hand it was serving as kind of a contract, which we as devs and the POs were committed to. Also we arranged that our POs wrote acceptance tests for the use case. With those newly introduced methods in our development process, confidence and trust increased and we kept our way of releasing and deploying after the feature is “Definition of Done” ready during the sprint.
Tests turn from verification to specification
Again time went by and as the FOs are sitting in another building and in contrast to our POs are feeling the need of manual tests, again the question for a fixed deployment-plan arose. Newly implemented features and more dependencies to other teams strengthened the need. To hold on to our flexibility and to keep deploying during our sprint we introduced a process called “3 Amigo Testing”. Before a story accomplishes the “Definition of Ready” and is thereby ready for our refinement the tests have to be written together with our FOs, our POs and us (one of the devs). Thereby tests turn from verification to specification no matter at which level: unit, integration or system integration! In addition the discussion not only improves the communication between the business and the technical team, it also helps to understand the complexity and the pitfalls early which results in a better estimation.
Time to grasp the nettle
Technically that means you need an abstraction on top of your automated tests. Behaviour tests should always be written from a customer’s point of view and describe the acceptance criteria of a use case. Important is, that you use a business readable language like gherkin. It describes a test in the form of an initial state (“given”), an action (“when”) and a final state (“then”) which is common in the BDD context. By that you have a description of a finite state machine which gives you the ability to describe a feature integrally. It does not matter at which level of the testing pyramide the actual implementation of the test is settled. A defined requirement may be implemented at unit level as well as at system integration level. We use cucumber because it meets the aforementioned requirements and because of existing knowledge and easy integration in our ecosystem. It is easy to use with the spring framework and gives us pretty jenkins reportings loved by our POs. But it is only one of many possible tools. Finally we recognized, that we established the building blocks of BDD:
Define tests beforehand - The specification of tests takes place before talking about the story in the refinement.
Use ubiquitous language - Defining the behaviour together with our POs and FOs we use a common language to avoid misunderstandings.
Express all requirements in high-level business terms from the customer point of view - The tests serve as the acceptance criteria of the story describing the next business value to deliver. Therefore it is defined from the customer’s perspective.
Accessible to all stakeholders - The tests, which now serve as documentation, are accessible to all stakeholders via a reporting plugin provided by our continuous integration tool.
With that said we built up not only the technical prerequisite to eliminate all manual tests but also gained trust and are now ready for continuous deployment. In addition our testsuite turns out to be a helpful backbone for our ongoing project of splitting a monolith into microservices.
If u want to know more about the project join us for our talk at Java User Group Karlsruhe!