Test-Driven Development (TDD) is a discipline that helps to create error-free, quality code, and drives productivity by reducing and eliminating errors as well as providing many other benefits.
This entry-level training course is designed to bring you quickly up to speed with the basic features and processes involved in performing Java based test-driven development using JUnit5. It covers the key principles and practices of test-driven development, which you can then utilize within your own software engineering projects.
In this course, you'll be guided through an end-to-end sample project in which we use test-driven development to build, test, and package a Java 11 based library that will provide an API to convert Bitcoins into foreign currency.
If you have any feedback relating to this course, please contact us at support@cloudacademy.com.
Learning Objectives
- Understand the fundamentals of TDD and JUnit5
- Use TDD to build, test, and package a Java 11 based library
- Perform TDD by performing Red-Green-Refactor iterations
- Learn how to use TDD to build, test, and package a Java 11 based library
- Learn how to create unit tests using the JUnit5 testing framework
Intended Audience
- Software developers interested in using TDD to build JDK11 based applications using Java
Prerequisites
To get the most out of this course, you should have a basic understanding of JDK11 and the Java programming language, as well as software development and the software development life cycle (SDLC).
Resources
Welcome back. In this demonstration, I'm going to do a final round of refactoring and also demonstrate how to implement unit test, that test for error conditions is up until now all of our unit test have always tested positive outcomes for our library, but we equally need to test how our library behaves when the environment in which is working is not up to scratch. For example, how does the library behave when we coined this Bitcoin API as offline?
Okay, let's get started. I'm going to jump into our unit testing file. I'll scroll down and and after the last get exchange right based unit test. I'll add in another unit test again exercising the gate exchange rate method but this time the state in which we're going to test is when the closing response throws an IO exception, and that our expectation is that it returns the right error code. In this case, a negative one. I'll save that.
I'll rerun our test they should fail. Yes they do and now I'll jump back over into our implementation. And this time I'm going to update a few things. The first of which is I'll take the opportunity to update the way in which we work with the response. Since our response is closable, I'll let Java take care of it at runtime when we no longer need it. I'll then jump down into the convert Bitcoins method, and this time I'll add an if statement it tests if the exchange rate is greater or equal to zero and if it is, I'll just return the normal dollars amount otherwise I'll set dollars to be negative one. I'll save that.
Okay, we'll run our tests. And excellent. The new test which tests for a failure condition passes. So we take a look at that test. We can see that we're testing for the state of the closing response, throwing an IO exception and when it does, we're returning the correct error code. So you can see here that our mock sits up and throws an IO exception on the response when it closes and that we were testing for negative one and it's the result we got back.
Okay. I'll scroll back down to the bottom of our unit test and this time I'll add in another unit test and this will be exercised on the convert Bitcoins method and it's going to test the condition of passing a negative Bitcoins and trying to convert them to USD and expecting that in exception is thrown in particular we'll be expecting an illegal argument exception. I'll save that. Rerun our tests, that will fail. I'll now update the implementation and all I'm going to do here is test with our coins which I'm passing in as less than zero and when it is I'm going to throw a new illegal argument exception.
The following string number of coins must not be less than zero. Well, I made it. I'll also take the opportunity to update the type of coins from ant to double that will allow us to pass and partial Bitcoins. Save that rerun and we're back to green. So our latest failure testing tests passes.
Finally, I want to add in one further test, again this whole exercise, the convert Bitcoins method and this time we're going to test when a 503 service unavailable response code is returned. Again, we'll expect a correct error code has returned. Again still being negative one. Save that run our test and indeed they pass. So that's a great result.
So what we've just proved is that our current implementation will behave correctly if when it goes live the response from the Coindesk API was to return a 503 service unavailable error code.
Now, one last thing I want to do before we complete the implementation is to address the fact that at the moment for our currency we're passing in these magic strings. So I want to convert these string values into an actual type which gives us type safety at compile time. So let's do that.
So what I'm going to do is I'm going to search for the string everywhere in our unit test and I'm going to replace it with a type which we haven't implemented yet. We'll call it currency. And it will be an enum containing values for USD Great British Pounds and Euros. So we'll do a global replacement with our now unit test file. Likewise, we'll do the same for Great British Pounds. and then also for Euro. We'll save that. We run our test they will fail. This is the read phase.
Now we need to update the implementation. Beneath the constructor, I'll create a new public enum that'll be called currency and I will have three possible values. USD Great British Pounds or Euro. Save that. I'll also check in here we'll need to update our get exchange rate I'm taking a string to taking a currency and likewise here. Save that. We'll clear the terminal we run our tests and we'll see what we get.
Okay. So we get a failure. Now, this is the great thing when you're in a refactoring phase. You can depend on your unit test to tell you about issues that you haven't anticipated. So here we must, part of the implementation we need to update line 46 cause we've got incompatible data types. So I've got to go to line 46 and then we've got to change this.
So it's now an enum so we need to call two string to convert it back to a string. Save that. Clear the terminal rerun our tests. And excellent. All 15 unit tests have gone back to green proving that our last minute change in refactoring is not only compatible but all of the behaviors are consistent as encoded within our unit test. This is a great result.
Okay, so at this stage we've finished the implementation of our Java Bitcoin library. In the next lesson I'm going to introduce GitHub actions as a method of doing CI/CD builds automatically for us, anytime that we check in or push up our new updated source code into our Github repo.
Go ahead and close this lesson and I'll see you shortly in the next one.
Jeremy is a Content Lead Architect and DevOps SME here at Cloud Academy where he specializes in developing DevOps technical training documentation.
He has a strong background in software engineering, and has been coding with various languages, frameworks, and systems for the past 25+ years. In recent times, Jeremy has been focused on DevOps, Cloud (AWS, Azure, GCP), Security, Kubernetes, and Machine Learning.
Jeremy holds professional certifications for AWS, Azure, GCP, Terraform, Kubernetes (CKA, CKAD, CKS).