Test-driven and Behavior-driven Development
Following Test-driven Development Principles with Copilot¶
Objective¶
In this exercise we will use Copilot in a TDD type of way, where we write the tests first and then generate the code to make them pass. For this exercise we will create a new controller called AuthorController
. This controller will return a message containing information about the main contributors to the project.
Scenario¶
We would like the user to see author information when they visit the /authors
endpoint of the service.
Steps¶
- Create a new file in
/dks-api/src/test/java/com/liatrio/dojo/devopsknowledgeshareapi/
namedAuthorControllerTest.java
- Add the following comment to the file
Let's generate the test for this first, using Copilot.
// get /authors
- Use either the Copilot inline prompt or the Copilot sidebar chat to ask Copilot to generate the tests from the comment.
Example (using the sidebar chat):
@workspace Generate tests for the pseudo code comment in #file:AuthorControllerTest.java. Keep the new tests consistent with existing tests in the project.
Note that the above prompt is using a context variable of type #file to tell Copilot what file to reference when creating functional tests. The context variable may not retain it's formatting after being copy+pasted, so make sure to update the formatting after copy+pasting the prompt into the Copilot chat. The context variable will be highlighted blue if the formatting is correct
- Review the feedback from Copilot. If everything looks good, copy the code to the newly created
AuthorControllerTest.java
file, located in the test directory -
Run the test (optional)
docker run -e GRADLE_USER_HOME='/app/.gradle' -e SPRING_PROFILES_ACTIVE=local --rm -v "$(pwd)":/app -w /app eclipse-temurin:17-jdk ./gradlew --info --no-daemon build
make build
The above command will:
- pull the eclipse-temurin:17-jdk image from Docker Hub
- create a docker volume in the current directory and map it to the /app directory in the container
- run the container with the following environment variables:
- GRADLE_USER_HOME='/app/.gradle'
- SPRING_PROFILES_ACTIVE=local
- set the working directory to the /app directory in the container
- execute the build gradle task, using the gradle wrapper to build and test the application
The test should fail, as we have not implemented the controller yet.
-
Using the Copilot sidebar chat, tell it to generate the code that will make the test pass. Example prompt (with the test selected)
Generate the method to make the tests in #file:AuthorControllerTest.java pass
Note that the above prompt is using a context variable of type #file to tell Copilot what file to reference when creating functional tests. The context variable may not retain it's formatting after being copy+pasted, so make sure to update the formatting after copy+pasting the prompt into the Copilot chat. The context variable will be highlighted blue if the formatting is correct.
- Review the code generated by Copilot. If everything looks good, copy the code to the
AuthorController.java
file. The new file should exist atsrc/main/java/com/liatrio/dojo/devopsknowledgeshareapi
, along with the existing controllers. - Run the test again to verify that it passes.
Eureka! You have successfully followed TDD principles with Copilot!
Tips¶
- The Sidebar chat is a great way to interact with Copilot for this approach. It provides additional context for it's solution and can be easier to do prompt adjustments, if the result is not what you're looking for.
- You can use the context box from the sidebar chat to either copy the code into the current file, or to copy it to a new file.
Following Behavior-driven Development Principles with Copilot¶
Objective¶
In a situation where you have been given a user story, Copilot can be used in the same fashion as TDD, but with the user story acting as the prompt. In this exercise, we will use a user story to generate functional tests and code to make them pass.
User Story
// Feature: Share Application Information
// As a user
// I want to see api information
// So that I can see info the creators want me to see
// Scenario: User visits the /info URL of the service
// Given the user is not logged in
// When the user visits the /info page
// Then the user should see the phrase "Welcome to the API version 1.0""
// And they should not see an error message
Steps¶
- Open the Copilot chat and use this prompt to start generating some functional tests. Here's an example prompt using the above user story.
Using the following user story, create functional test cases to verify requirements have been met. Create tests that align with the pattern of existing tests in #file:HealthCheckTest.java. Include any necessary dependency imports. Feature: Share Application Information As a user I want to see api information So that I can see info the creators want me to see Scenario: User visits the /info URL of the service Given the user is not logged in When the user visits the /info page Then the user should see the phrase "Welcome to the API version 1.0"" And they should not see an error message Feature: Share Application Information As a user I want to see api information So that I can see info the creators want me to see Scenario: User visits the /info URL of the service Given the user is not logged in When the user visits the /info page Then the user should see the phrase "Welcome to the API version 1.0"" And they should not see an error message
Note that the above prompt is using a context variable of type #file to tell Copilot what file to reference when creating functional tests. The context variable may not retain it's formatting after being copy+pasted, so make sure to update the formatting after copy+pasting the prompt into the Copilot chat. The context variable will be highlighted blue if the formatting is correct
- Review the generated test code. If it looks good, copy it to a new file named
InfoControllerTest.java
, located in the functional test directorysrc/functionalTest/java/com/liatrio/dojo/devopsknowledgeshareapi/functional
- Using Copilot, generate the code that will make the test pass.
Example prompt (with the test selected)
Generate an info controller to make the test in #file:InfoControllerTest.java pass. Create a controller that aligns with the patterns seen in #file:PostController.java.
- Review the code generated by Copilot. If everything looks good, copy the code into a file called
InfoController.java
located atsrc/main/java/com/liatrio/dojo/devopsknowledgeshareapi
. -
Build and Run the application. The application needs to be running to execute the functional tests.
Build
docker network create backend docker run -e GRADLE_USER_HOME='/app/.gradle' -e SPRING_PROFILES_ACTIVE=local --rm -v "$(pwd)":/app -w /app eclipse-temurin:17-jdk ./gradlew --info --no-daemon bootJar docker build -t dks-api:$(git rev-parse --short HEAD) .
make docker-build
Run
docker run --name dks-api --network backend -p 8080:8080 --rm dks-api:$(git rev-parse --short HEAD)
make up
-
Execute the functional tests
docker run -e GRADLE_USER_HOME='/app/.gradle' -e SPRING_PROFILES_ACTIVE=local --rm -v "$(PWD)":/app -w /app --network backend eclipse-temurin:17-jdk ./gradlew --info --no-daemon functionalTest --rerun-tasks
make functional-test
Congratulations! You've used Copilot to generate tests and code that meet the requirements of a user story!
Tips¶
Think Behavior Driven Development: This first step is about using Copilot in a BDD type of way, where you write out the requirements and then generate the tests and code to make them pass.
- Once the user story is satisfactory, use Copilot to generate the tests for the user story.
- Tell Copilot to generate the code to make the tests pass.
Tips¶
Verify what the test is doing: The generated steps may not be what you expect. Assess and verify the correctness of the steps.
Pay attention to the save location: Make sure the file goes in the correct location.
Challenge¶
If you finish early, try to think of some new requirements and/or steps to add. Use Copilot and see how it does on modifying the suggestions, based on the new requirements or steps.