1. Home
  2. Training Library
  3. .NET Core C# - Test Driven Development (TDD) using xUnit

Refactor Codebase with Async/Await for HTTP Calls to the Coindesk Bitcoin API

Start course


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 C# based test-driven development using xUnit. 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 .NET Core 3.1 C# 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 xUnit
  • Use TDD to build, test, and package a .NET Core 3.1 C# based library
  • Perform TDD by performing Red-Green-Refactor iterations
  • Learn how to use TDD to build, test, and package a .NET Core 3.1 C# based library
  • Learn how to create unit tests using the xUnit testing framework

Intended Audience

  • Software developers interested in using TDD to build .NET Core applications using C#


To get the most out of this course, you should have a basic understanding of .NET Core and the C# programming language, as well as software development and the software development life cycle (SDLC).



Okay, welcome back. So in this demonstration, I'm now going to actually implement the Http calls to the CoinDesk API to get us our real-time information about the current exchange rates for Bitcoins and different currencies. Along the way, I'm also going to introduce you to the async await keywords that the .NET C# language provides, which provides an abstraction for doing asynchronous processes.

Now, we do so because we're reaching out to the CoinDesk API, which involves latency in terms of the response coming back. Anyway, this will become clearer as we proceed. To begin with, I want to show you the actual API that we're going to be calling. So this is the URL. It's provided by CoinDesk. And we simply call it, and it returns basically a JSON payload containing the information about the current Bitcoin conversion or exchange rate for a particular currency. Here we can see for USD, the conversion rate is this value here. For great British pounds, the conversion rate is this number here. And for Euros, the conversion value is this guy here. 

So let's begin. So we'll jump back into our code. Now, in terms of our unit tests, we're just going to leave them as is. And instead we're going to jump into our implementation and we're going to refactor it to use a live call to that particular API. So, the first thing I'll do is up the top, I'll introduce a new constant, and this will contain the Bitcoin_CurrentPrice_URL. Okay, so that is the end point that we're going to communicate with. Save that. Notice our .NET tests automatically kick in, and are still passing.

So, as mentioned, I want to update the fact that we're going to use the async await pattern or abstraction provided by the .NET core framework. So, the first thing I'll do is that in my unit tests, I'm going to update all of them to use or expect the fact that we're going to be doing async await.

So, to introduce this, we go async, and then we pair it up with our await on the method that we're calling asynchronously, which will be our GetExchangeRate method. And that's all we have to do. So we'll repeat this on each of our unit tests. Save this. This will kick off our unit tests again, and this will fail. So we're now in the red phase. So we need to update our implementation to also be using async await.

So, for our GetExchangeRate method in our implementation I'm going to update this. It's going to be an async, and instead of returning an int, we're going to return a task of type double. So a task is closely aligned with the async await abstraction that the .NET framework provides. I'll jump back up to our using statements and I'll import System.Net.Http for our Http cons. I'll also import System.Threading.Tasks for our async await requirements. I'll also import System.Text and System.Text.Json, the reasons being for the last two is to allow us to parse the Json that is given back from our API calls from CoinDesk.

So now I want to update our fictitious implementation and actually call the CoinDesk API. So, first thing I'll do is I'll make a request using await. And we use the HttpClient GetStringAsync, and calling our URL. Okay, so the response here is going to contain this payload.

Now, let's update the implementation within each of the if branches. We'll want to get the JsonDoc out of our response. We'll want to parse it, and we need to specify the encoding, ASCII, and we'll use the GetBytes method on the ASCII object to return the bytes of our response to the JsonDocument.Parse method like so. And then we want to extract the rate. This is the currency rate. So we'll do it like so. JsonDoc.RootElement.GetProperty.

We need to go via this guy here, bpi.currency. In this case, USD. And then finally, we want to return the rate. Okay, so there we'll get our rate value. And then finally we need to return its equivalent double value, so we need to parse it, passing and rate, and we'll do GetString on that. Okay, looks good. We'll save that. And then we'll simply repeat this in our other if else blocks.

Okay. We can still do some tidy ups, but we'll just save that for now. And then we'll update our ConvertBitcoins method as well. So here we'll change this to async Task double, and then we simply add the await keyword to our call to GetExchange. Save that. Oh, we've got a minor issue here. This should be a method call. Save that again. So the good news is that this is now compiled, but our unit tests have failed. Can you guess why? So the reason being that our unit tests failed, is that we're still having expectations on those original fictitious amounts.

So, if you look at our first one, when we are testing the GetExchangeRate for USD dollars, we're expecting a value of 100. This was the original fictitious amount that I made up in the first version of our unit test. So we need to update this with the live amount. But I'm not going to do that because remember now that our implementation is actually dependent on an external service, and therefore our unit test has now actually become an integration test.

So how do we get it back to being a unit test? Well, we need to mock out the dependency on that API, and that will be the focal point of the next demonstration.

So, go ahead and close this demonstration and I'll see you shortly in the next one.

About the Author
Learning paths38

Jeremy is the DevOps Content Lead at Cloud Academy where he specializes in developing technical training documentation for DevOps.

He has a strong background in software engineering, and has been coding with various languages, frameworks, and systems for the past 20+ years. In recent times, Jeremy has been focused on DevOps, Cloud, Security, and Machine Learning.

Jeremy holds professional certifications for both the AWS and GCP cloud platforms.