Writing Java Code and Unit Tests Faster with GitHub Copilot

Featured image for “Writing Java Code and Unit Tests Faster with GitHub Copilot”

Writing Java Code and Unit Tests Faster with GitHub Copilot

August 11, 2025


In this post, we’ll explore how to use GitHub Copilot to generate Java code and unit tests with minimal manual input. Using a real-world example—a mortgage calculator service—you’ll see how Copilot can help write both the core logic and the corresponding unit tests. Whether you’re new to AI-assisted development or curious about Copilot’s capabilities in a Java environment, this tutorial will give you practical insight into how it works—and where human oversight still matters.

Way back in 2012, I wrote a blog post “Introducing Spring Batch, Part One,” which turned into a series that still gets a lot of traffic this many years later. One of the key points I emphasized was how the Spring Batch framework provides a substantial portion of the necessary infrastructure for batch processing, enabling your focus to be on addressing business problems.

Fast forward to today, AI tools like GitHub Copilot are offering a similar boost in productivity. Using Copilot to generate unit tests not only saves time but also improves test coverage and developer velocity.

At the client I’m currently working with, we recently switched to using JetBrains IntelliJ and introduced GitHub Copilot into our coding processes. Although we’re just getting started with the tool, it’s been quite an eye-opener in terms of increasing development quality and efficiency.

What is GitHub Copilot?

First, let’s talk about what GitHub Copilot is and how to obtain the tool.

According to the GitHub Copilot website, the simple definition is this: “GitHub Copilot is an AI coding assistant that helps you write code faster and with less effort, allowing you to focus more energy on problem solving and collaboration.”

Sounds very much like the point I made over 13 years ago about a framework, and from my limited experience it fits that description beautifully. It provides a whole suite of features to make development more efficient and provide better quality, but I’m going to narrow the focus in this article on using GitHub Copilot to generate unit tests. (Related: Blood, Sweat, and Writing Automated Integration Tests for Failure Scenarios.) First, we must obtain a GitHub Copilot license.

How to Get Started With Copilot

To get a GitHub Copilot license, you’ll need to choose a plan that fits your needs and sign up through GitHub. It’s simple; here’s how to go about it:

1. Visit the Copilot Plans Page
Head to the GitHub Copilot Plans page to compare available options.

2. Choose Your Plan
GitHub offers several tiers:

  • Free: Limited access; available to verified students, teachers, and open-source maintainers.
  • Pro: $10/month or $100/year for individuals.
  • Pro+: $39/month for advanced features and more premium requests.
  • Business: $19/seat/month for teams with centralized management.
  • Enterprise: $39/seat/month with enterprise-grade capabilities.

3. Sign In to GitHub
You’ll need a GitHub account. If you don’t have one, create it here.

4. Subscribe to a Plan
Once signed in, follow the prompts to subscribe. You can pay monthly or annually, and some plans offer a 30-day free trial.

5. Activate in Your IDE
After subscribing, enable Copilot in your preferred IDE (like VS Code or JetBrains) via the extension marketplace.

Generating Code and Unit Tests with Copilot

Now that we’ve got the necessary prerequisites out of the way, let’s start using GitHub Copilot. There are several different ways to interact and use the tool, but for this quick example, I’m going to show you how to use the GitHub Copilot Chat.

Somewhere in your IDE of choice, you’ll see the GitHub Copilot Chat icon like in the screenshot below. I’m using IntelliJ, and it might look like this, depending on how you have your IDE configured. When you click the icon, it will pop open a panel similar to the one below.

image showing how to get started with github copilot

At the bottom of the panel, you will see an interactive chat window with an option to choose the chat model in the dropdown, similar to the one shown in the screenshot below.

Image showing where the copilot chat model is

Example: Mortgage Calculator Service in Java

One thing I always struggle with is coming up with good examples for these blog articles. Many blogs I read tend to use fairly simple examples, which is great for introducing a topic. However, in this case, I want to showcase how useful the tool can be for everyday coding purposes that involve somewhat complex business logic.

After mulling it over quite a bit, I decided to see how well GitHub Copilot Chat could produce a service for calculating a mortgage payment and amortization schedule.

Here’s what I asked GitHub Copilot to produce:

a screenshot of a sample prompt I used to get started with github copilot

After about 10 seconds, here’s what it responded with (Note: the full code listing is at the end of the article):

Example: Copilot-Generated Unit Tests

Notice at the bottom of the GitHub Copilot Chat results that it has suggested a follow-up prompt that asks, “Can you help me write unit test for the MortgageCalculationService?” It’s like it has read my mind, or maybe it’s just a common request. Once I click the link, after a few seconds, it generated the following (don’t miss the full code listing at the end of the article):

Screenshot of Github Copilot response

This also included a summary explanation of what was included in the response:

Screenshot of GitHub Copilot summary explanation of what was included in the response

Example: Java Unit Testing with Copilot Takeaways

The request and response to write the service and generate a unit test for this example took less than 30 seconds. Before GitHub Copilot was available as a tool, I would have had to write the service and unit tests by hand with only code completion built into the IDE to assist me.

I would change a couple of things, though. For instance, I would modify the generateAmortizationSchedule method in the MortgageCalculatorService to return an object that encapsulates the payment number, principal balance left, interest paid, principal paid, and total payment. I might have also added some potential logging, validation, and error handling to the service. The unit test provides a pretty solid test, but any enhancements I make to the service would also need to be updated in the unit test. I would also look at adding any edge cases or error handling tests to the unit test.

Tips to Improve Copilot’s Unit Test Suggestions

Here are some tips to help improve your success while using GitHub Copilot to help generate unit tests:

⚙️ 1. Use Descriptive Method Names

Copilot thrives on context. Instead of testMethod1, go with something like:

@Test public void testCalculateDiscount_withValidInputs_returnsCorrectValue() { 

This tells Copilot what the test should do, and it often fills in the rest of the details.

🧠 2. Keep Source Code Visible

Open the class or method you’re testing in a split view. Copilot uses surrounding context to generate relevant assertions and setup code.

🧪 3. Prompt with Comments

Before writing a test, add a comment like:

// Test calculateDiscount with price=100 and discountRate=0.2, expecting 80 

Copilot will often generate the full test method based on that alone.

🧹 4. Focus on Edge Cases

Copilot handles happy paths well, but you can guide it toward edge cases:

  • Zero or negative inputs
  • Null values
  • Exception handling

Example prompt:

// Test calculateDiscount with negative price, should throw IllegalArgumentException 

🧰 5. Use Parameterized Tests

If you’re using JUnit 5, Copilot can help generate @ParameterizedTest methods to cover multiple scenarios efficiently. (This may have made Conditionally Disabling Tests in JUnit 5 a little bit easier back in the day!)

📐 6. Review and Refactor

Copilot gives you a solid draft, but when using GitHub Copilot for Java or any other language, always:

  • Check for missing assertions
  • Validate mock behavior
  • Ensure test isolation

Conclusion: Copilot as a Developer Tool

In conclusion, while AI tools like Copilot can significantly accelerate the process of writing and refining tests, the ultimate responsibility for robust, high-quality code remains with the developer. Taking the time to review, enhance, and expand upon generated tests thoughtfully ensures that your codebase is not only well-covered but also maintainable and reliable for the future.

As this Java unit testing example has shown, GitHub Copilot is not a replacement for good engineering practices. But when used thoughtfully, it boosts productivity and helps developers focus on logic, quality, and innovation.

By combining the efficiency of AI with diligent engineering practices, you can create quality software that stands up to real-world challenges. On a related note, you might like John Hoestje’s blog post on creating an AI-powered assistant in his IDE with Agentic AI.

Are you exploring AI-powered development tools like GitHub Copilot for your team? Our expert consultants can help you integrate modern solutions like AI into your software lifecycle through our AI-Accelerated Development Services. [Contact Keyhole Software →]

Full Java Code Listing

package com.example.mortgage;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

public class MortgageCalculatorService {

    /**
     * Calculates the monthly payment for a fixed-rate mortgage.
     *
     * @param principal The loan amount
     * @param annualInterestRate The annual interest rate (e.g., 0.05 for 5%)
     * @param years The term of the loan in years
     * @return The monthly payment
     */
    public BigDecimal calculateMonthlyPayment(BigDecimal principal, BigDecimal annualInterestRate, int years) {
        BigDecimal monthlyRate = annualInterestRate.divide(BigDecimal.valueOf(12), 10, RoundingMode.HALF_UP);
        int totalPayments = years * 12;

        if (monthlyRate.compareTo(BigDecimal.ZERO) == 0) {
            return principal.divide(BigDecimal.valueOf(totalPayments), 2, RoundingMode.HALF_UP);
        }

        BigDecimal numerator = principal.multiply(monthlyRate)
                .multiply((BigDecimal.ONE.add(monthlyRate)).pow(totalPayments));
        BigDecimal denominator = (BigDecimal.ONE.add(monthlyRate)).pow(totalPayments).subtract(BigDecimal.ONE);

        return numerator.divide(denominator, 2, RoundingMode.HALF_UP);
    }

    /**
     * Generates an amortization schedule.
     *
     * @param principal The loan amount
     * @param annualInterestRate The annual interest rate
     * @param years The term of the loan in years
     * @return List of remaining balances after each payment
     */
    public List<BigDecimal> generateAmortizationSchedule(BigDecimal principal, BigDecimal annualInterestRate, int years) {
        List<BigDecimal> schedule = new ArrayList<>();
        BigDecimal monthlyPayment = calculateMonthlyPayment(principal, annualInterestRate, years);
        BigDecimal monthlyRate = annualInterestRate.divide(BigDecimal.valueOf(12), 10, RoundingMode.HALF_UP);
        BigDecimal balance = principal;
        int totalPayments = years * 12;

        for (int i = 0; i < totalPayments; i++) {
            BigDecimal interest = balance.multiply(monthlyRate).setScale(2, RoundingMode.HALF_UP);
            BigDecimal principalPaid = monthlyPayment.subtract(interest);
            balance = balance.subtract(principalPaid).setScale(2, RoundingMode.HALF_UP);
            if (balance.compareTo(BigDecimal.ZERO) < 0) {
                balance = BigDecimal.ZERO;
            }
            schedule.add(balance);
        }
        return schedule;
    }
}


package com.example.mortgage;

import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

class MortgageCalculatorServiceTest
{

    private final MortgageCalculatorService service = new MortgageCalculatorService();

    @Test
    void testCalculateMonthlyPayment()
    {
        BigDecimal principal = new BigDecimal("200000");
        BigDecimal annualInterestRate = new BigDecimal("0.05");
        int years = 30;

        BigDecimal expectedMonthlyPayment = new BigDecimal("1073.64");
        BigDecimal actualMonthlyPayment = service.calculateMonthlyPayment(principal, annualInterestRate, years);

        assertEquals(expectedMonthlyPayment, actualMonthlyPayment, "Monthly payment calculation is incorrect");
    }

    @Test
    void testCalculateMonthlyPaymentWithZeroInterest()
    {
        BigDecimal principal = new BigDecimal("120000");
        BigDecimal annualInterestRate = BigDecimal.ZERO;
        int years = 15;

        BigDecimal expectedMonthlyPayment = new BigDecimal("666.67");
        BigDecimal actualMonthlyPayment = service.calculateMonthlyPayment(principal, annualInterestRate, years);

        assertEquals(expectedMonthlyPayment, actualMonthlyPayment, "Monthly payment with zero interest is incorrect");
    }

    @Test
    void testGenerateAmortizationSchedule()
    {
        BigDecimal principal = new BigDecimal("100000");
        BigDecimal annualInterestRate = new BigDecimal("0.04");
        int years = 15;

        List<BigDecimal> schedule = service.generateAmortizationSchedule(principal, annualInterestRate, years);

        assertEquals(180, schedule.size(), "Amortization schedule should have 180 payments");
        assertEquals(BigDecimal.ZERO, schedule.get(schedule.size() - 1), "Final balance should be zero");
    }

    @Test
    void testGenerateAmortizationScheduleWithZeroInterest()
    {
        BigDecimal principal = new BigDecimal("50000");
        BigDecimal annualInterestRate = BigDecimal.ZERO;
        int years = 10;

        List<BigDecimal> schedule = service.generateAmortizationSchedule(principal, annualInterestRate, years);

        assertEquals(120, schedule.size(), "Amortization schedule should have 120 payments");
        assertEquals(BigDecimal.ZERO, schedule.get(schedule.size() - 1), "Final balance should be zero");
    }
}

 

About The Author

More From Jonny Hackett

About Keyhole Software

Expert team of software developer consultants solving complex software challenges for U.S. clients.

Share This Post

Related Posts


Discuss This Article

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments