Automatically generate unit tests for Kotlin projects

Diffblue HQ
5 min readMar 7, 2024

Diffblue Cover represents a breakthrough in automated testing, providing developers with a powerful tool to write unit tests quickly and efficiently. Initially designed for Java, its capabilities can extend to Kotlin projects, offering a seamless integration for a wide range of applications.

This post is designed to guide developers and engineering team leaders through the innovative approach of using Diffblue Cover to automatically write unit tests for Kotlin codebases.

Before diving into the specifics, it’s essential to understand that this article assumes a basic familiarity with Kotlin and unit testing principles. Throughout the article, we’ll use the Spring PetClinic Kotlin codebase to demonstrate practical applications of Diffblue Cover in a real-world project.

Getting Started with Diffblue Cover in Your Kotlin Project

For demonstration purposes, we’re using the Spring PetClinic Kotlin codebase — a familiar example for many Spring Boot Developers.

Integrating Diffblue Cover into your Kotlin project is straightforward.

Diffblue Cover can be added to your project through its plugin for IntelliJ IDEA or via the CLI (Command Line Interface), offering flexibility in how you prefer to work.

For this article, we’re going to use the CLI version. To get started, enroll for a free trial and download and install Cover CLI as per the documentation.

Once the Cover CLI is set up, ensure you can build the Spring PetClinic project with ./gradlew build and the preflight check of the CLI is successful.

$ dcover create --preflight

Writing Your First Test with Diffblue Cover

To enrich the article with a practical example, let’s walk through the process of using Diffblue Cover to write unit tests for a Kotlin class within the Spring PetClinic Kotlin codebase.

We’ll focus on a simplified version of a controller class, org.springframework.samples.petclinic.owner.PetController, responsible for managing pet information:

@Controller
@RequestMapping("/owners/{ownerId}")
class PetController(val pets: PetRepository, val owners: OwnerRepository) {


private val VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"


@PostMapping("/pets/new")
fun processCreationForm(owner: Owner, @Valid pet: Pet, result: BindingResult, model: Model): String {
if (StringUtils.hasLength(pet.name) && pet.isNew && owner.getPet(pet.name!!, true) != null) {
result.rejectValue("name", "duplicate", "already exists")
}
owner.addPet(pet)
return if (result.hasErrors()) {
model["pet"] = pet
VIEWS_PETS_CREATE_OR_UPDATE_FORM
} else {
this.pets.save(pet)
"redirect:/owners/{ownerId}"
}
}
}

Let’s look at how we can use Cover to create unit tests for this HTTP POST controller endpoint. Therefore, we’ll use the CLI and point to the fully-qualified class name of the PetController:

$ dcover create org.springframework.samples.petclinic.owner.PetController

Running this command will trigger Diffblue Cover to create a set of tests for our entire controller class. As a result, we’ll find a new test class PetControllerDiffblueTest within src/test/java:

@ContextConfiguration(classes = {PetController.class})
@ExtendWith(SpringExtension.class)
class PetControllerDiffblueTest {


@MockBean
private OwnerRepository ownerRepository;


@Autowired
private PetController petController;


@MockBean
private PetRepository petRepository;


@Test
void testProcessCreationForm() throws Exception {
// Arrange
when(petRepository.findPetTypes()).thenReturn(new ArrayList<>());


Owner owner = new Owner();
owner.setAddress("42 Main St");
owner.setCity("Oxford");
owner.setFirstName("Jane");
owner.setId(1);
owner.setLastName("Doe");
owner.setPets(new HashSet<>());
owner.setTelephone("6625550144");
when(ownerRepository.findById(anyInt())).thenReturn(owner);
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/owners/{ownerId}/pets/new", 1);


// Act and Assert
MockMvcBuilders.standaloneSetup(petController)
.build()
.perform(requestBuilder)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.model().size(3))
.andExpect(MockMvcResultMatchers.model().attributeExists("owner", "pet", "types"))
.andExpect(MockMvcResultMatchers.view().name("pets/createOrUpdatePetForm"))
.andExpect(MockMvcResultMatchers.forwardedUrl("pets/createOrUpdatePetForm"));
}


// more tests for this controller endpoint
}

This auto-created test class contains test methods for all controller endpoints of the PetController.Cover automatically writes a set of unit tests for each controller endpoint to cover various scenarios.

We can immediately run the tests as Diffblue ensures the auto-created test compiles and executes successfully.

Seeing the test result for the first time, you might wonder why the result is a Java test class. As of now, Diffblue Cover only supports Java test classes as an output format. However, there’s a simple way to automatically convert this test to Kotlin, if needed.

Bonus Tip: Converting Java Unit Tests to Kotlin with IntelliJ IDEA

Converting Java unit tests into Kotlin using IntelliJ’s conversion feature facilitates a smoother transition for companies migrating from Java to Kotlin. This capability not only streamlines the adaptation process by automating the conversion of existing test suites, but also ensures that legacy tests remain functional and relevant in the new Kotlin codebase.

Such a feature is particularly valuable for maintaining test coverage and quality assurance during the migration, allowing teams to leverage Kotlin’s concise syntax and modern features without losing the robustness of their Java-based tests.

To convert Java unit tests into Kotlin in IntelliJ IDEA, follow this: Open the Java test file in IntelliJ, then from the main menu, select Code > Convert Java File to Kotlin File.

Running this action for our auto-created Java test class PetControllerDiffblueTest, we'll get the following result:

 /**
* Method under test:
* [PetController.processCreationForm]
*/
@Test
@Throws(Exception::class)
fun testProcessCreationForm3() {
// Arrange
Mockito.`when`(petRepository!!.findPetTypes()).thenReturn(ArrayList())


val owner = Owner()
owner.address = "42 Main St"
owner.city = "Oxford"
owner.firstName = "Jane"
owner.id = 1
owner.lastName = "Doe"
owner.pets = HashSet()
owner.telephone = "6625550144"
Mockito.`when`(ownerRepository!!.findById(ArgumentMatchers.anyInt())).thenReturn(owner)
val requestBuilder = MockMvcRequestBuilders.post("/owners/{ownerId}/pets/new", 1)
requestBuilder.contentType("text/plain")


// Act and Assert
MockMvcBuilders.standaloneSetup(petController)
.build()
.perform(requestBuilder)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.model().size(3))
.andExpect(MockMvcResultMatchers.model().attributeExists("owner", "pet", "types"))
.andExpect(MockMvcResultMatchers.view().name("pets/createOrUpdatePetForm"))
.andExpect(MockMvcResultMatchers.forwardedUrl("pets/createOrUpdatePetForm"))
}

This automatic conversion helps us quickly get the Diffblue Cover unit test as a Kotlin test class.

Integrating Diffblue Cover Into Your Daily Workflow

Integrating Diffblue Cover into your daily workflow can revolutionize how your team approaches testing. Here are some ways to make the most out of this tool:

  • Continuous Integration (CI): Implement Diffblue Cover in your CI pipeline, such as GitLab CI, to automatically write and run tests on every commit. This ensures immediate feedback on the impact of changes, facilitating a test-driven development (TDD) approach.
  • Development Cycle: Use Diffblue Cover during development to instantly write tests for new features or bug fixes, enabling a shift-left testing culture where issues are identified and resolved early in the development process.

Reasons to use Diffblue Cover for unit test writing

Incorporating Diffblue Cover into your development and testing workflows offers numerous advantages:

  • Time Savings: Automate the creation of unit tests, freeing developers to focus on feature development and code quality improvements.
  • Quality Assurance: Enhance the robustness of your codebase with comprehensive tests, reducing the risk of regressions and bugs.
  • Versatility: Though we’ve focused on Kotlin, remember that Java is the main programming Diffblue Cover supports, making it a versatile tool for projects using both languages.

Summary: Using Diffblue Cover for Kotlin Codebases

Diffblue Cover presents a transformative approach to automated testing for Kotlin developers. By leveraging its capabilities to write unit tests automatically, teams can ensure higher code quality, reduce manual testing efforts, and streamline their development cycles.

The Spring PetClinic Kotlin codebase serves as an excellent example of how Diffblue Cover can be applied to real-world projects, demonstrating its effectiveness in enhancing software reliability and developer productivity.

Why not try Diffblue Cover for yourself? You can get started with a free trial .

Originally published at https://www.diffblue.com on March 7, 2024.

--

--

Diffblue HQ

Diffblue Cover autonomous AI-powered Java unit test suite generation & maintenance at scale. | We’re making developers wildly more productive with AI for Code