Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon

Writing Unit Tests in C# with ease using ChatGPT

Save for later
  • 9 min read
  • 08 Jun 2023

article-image

The world is abuzz with talk of large language model AI, especially its iconic ChatGPT. No one is more excited and perhaps threatened than programmers. Will ChatGPT soon write code well enough to change or even eliminate our jobs? In this article, I set such concerns aside and focus on how ChatGPT can enhance our programming today. 

One of the places I find ChatGPT most useful is in the writing of unit tests. To illustrate this, I'm going to dip into the source code used in my latest book: .NET MAUI For C# Developers. If you haven't read my book (actually, why not stop here and run out and buy it? I can wait here) it illustrates the creation of a helpful app that, among other things, requires you to create an account. Here is the code for doing so: 

  [RelayCommand] 
  async Task SignUp() 
  { 
    if (EnableButton) 
    { 
      AccountCreateRequest accountCreateRequest = new() 
      { 
        Email = this.Email, 
        FullName = Name, 
        PlainPassword = Password 
      }; 
 
      try 
      { 
        CreateAccountIsRunning = true; 
        await accountService.CreateAccount(accountCreateRequest); 
        CreateAccountIsRunning = false; 
        await Application.Current.MainPage.DisplayAlert( 
        "Sign up completed", 
        "Your user has been created successfully", "Ok"); 
        await Shell.Current.GoToAsync(".."); 
      } 
      catch (Exception e) 
      { 
          CreateAccountIsRunning = false; 
        await Application.Current.MainPage.DisplayAlert( 
        "Sign up failed", 
        "We were not able to create an account with that user name", 
        "Ok"); 
      } 
    } 
 
  } 

The logic here is simple, I've selected it specifically so that you can easily imagine how you would write unit tests. Let's see how ChatGPT does when presented with this code. I opened ChatGPT and entered the following message: 
 

Write two unit tests with xUnit and nSubstitute in C# for the following .NET MAUI code 

(I pasted in the code. It responded so quickly it took my breath away)

Sure! Here are two unit tests using xUnit and NSubstitute for the SignUp() method: 

I particularly like the self-assured and friendly "Sure!" at the beginning, and the restatement of what it has been asked to do. Its results come flying out in a box that has a handy Copy Code button on the top right, and a reminder on the top left that the code is in C# as shown in the figure: 

 
writing-unit-tests-in-c-with-ease-using-chatgpt-img-0 

Figure 1 – top of ChatGPT response  

Notice that it marks the first section. 

// Arrange 

As you'll see it uses and annotates the AAA approach to unit tests (Arrange, Act, Assert). Here are the two-unit tests it produced: 

public class YourViewModelTests 
{ 
    [Fact] 
    public async Task SignUp_WhenEnableButtonIsFalse_DoesNotCallAccountServiceAndDisplaysNoAlert() 
    { 
        // Arrange 
        var accountService = Substitute.For<IAccountService>(); 
        var applicationMock = Substitute.For<Application>(); 
        var mainPageMock = Substitute.For<Page>(); 
        var shellMock = Substitute.For<Shell>(); 
 
        applicationMock.MainPage = mainPageMock; 
        Shell.Current = shellMock; 
 
        var viewModel = new YourViewModel(accountService) 
        { 
            Email = "test@example.com", 
            Name = "John Doe", 
            Password = "password", 
            EnableButton = false 
        }; 
 
        // Act 
        await viewModel.SignUp(); 
 
        // Assert 
        await accountService.DidNotReceive().CreateAccount(Arg.Any<AccountCreateRequest>()); 
        await applicationMock.MainPage.DidNotReceive().DisplayAlert(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>()); 
        await shellMock.DidNotReceive().GoToAsync(Arg.Any<string>()); 
    } 
 
    [Fact] 
    public async Task SignUp_WhenEnableButtonIsTrue_CallsAccountServiceAndDisplaysAlertOnError() 
    { 
        // Arrange 
        var accountService = Substitute.For<IAccountService>(); 
        accountService 
            .When(x => x.CreateAccount(Arg.Any<AccountCreateRequest>())) 
            .Throw(new Exception("Failed to create account")); 
 
        var applicationMock = Substitute.For<Application>(); 
        var mainPageMock = Substitute.For<Page>(); 
        var shellMock = Substitute.For<Shell>(); 
 
        applicationMock.MainPage = mainPageMock; 
        Shell.Current = shellMock; 
 
        var viewModel = new YourViewModel(accountService) 
        { 
            Email = "test@example.com", 
            Name = "John Doe", 
            Password = "password", 
            EnableButton = true 
        }; 
 
        // Act 
        await viewModel.SignUp(); 
 
        // Assert 
        await accountService.Received(1).CreateAccount(Arg.Is<AccountCreateRequest>(request => 
            request.Email == viewModel.Email && 
            request.FullName == viewModel.Name && 
            request.PlainPassword == viewModel.Password)); 
 
        await applicationMock.MainPage.Received(1).DisplayAlert("Sign up failed", 
            "We were not able to create an account with that user name", "Ok"); 
 
        await shellMock.DidNotReceive().GoToAsync(Arg.Any<string>()); 
    } 
} 

 After the code comes to these handy instructions and reminders: 

In the first test case, SignUp_WhenEnableButtonIsFalse_DoesNotCallAccountServiceAndDisplaysNoAlert(), we set EnableButton to false and verify that the SignUp() method does not call CreateAccount() on the accountService, and no alerts are displayed. 

In the second test case, SignUp_WhenEnableButtonIsTrue_CallsAccountServiceAndDisplaysAlertOnError(), we set EnableButton to true and configure the accountService to throw an exception when CreateAccount() is called. We verify that the method calls CreateAccount(), displays the appropriate alert for failure, and does not navigate to another page using GoToAsync(). 

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime

By following those instructions, I had two working, useful unit tests, literally in seconds (well, a lot of seconds, but only because it took me a minute to read and understand (and verify) what it had done.) 

The first time I made the request, I forgot to say it in xUnit and it spits out the tests in nUnit. I then entered, 

Do it again using xUnit 

And it didn't hesitate, out came the code in xUnit along with modified instructions. 

Summary 

In sum, my pair-programming buddy, ChatGPT, saved me a lot of tedious work creating unit tests. I can attest that it works equally well on more complex logic. It doesn't always get it right the first time, but you can "tune" it with follow-up questions, and it remembers what it just did, so rather than repeating the entire command you can just say, as I do above, Do it again, but this time…

 We used to say, Coding by Google is not a problem as long as you know what you are doing. The problem only arose with very junior programmers who took what they found online as-is without checking that it made sense. The same can be true here: ChatGPT can get you going, and you can often use its code as-is, but you need to keep a cautious eye on it as it certainly can get things wrong. 

 Writing unit tests is a critical, though often overlooked part of writing code well. ChatGPT not only makes it relatively easy, but it also encourages creating tests because you can do so quickly. It is so good that I happily pay $20/month for a subscription entitling me to unrestricted use and access to the latest iteration. 

 

Author Bio 

 Jesse Liberty is a full-time hands-on programmer, specializing in C#, git, and .NET MAUI. He hosts the popular Yet Another Podcast and is the author of more than a dozen best-selling programming books. Liberty is a Certified Xamarin Developer, a Xamarin MVP, and a Microsoft MVP. He was a Technical Evangelist for Microsoft, a Distinguished Software Engineer at AT&T; a Software Architect for PBS, and a Vice President of Information Technology at Citibank, and he was on the teaching staff at Brandeis University. Jesse is a recognized expert and has spoken at conferences worldwide. 

 

Links - LinkedIn  .NET MAUI for C# Developers