Randoop: automatic JUnit test generation for Java classes
Automatic test generation for Java
At a glance
- What is it?
- Randoop is a unit test generator for Java that creates tests for your classes in JUnit format, using Java agents that rewrite bytecode at load time to observe what your code actually does. It is MIT licensed, Gradle built, and its own test suite is organised with a system test layer separate from its unit tests.
- Who is it for?
- Adopt Randoop if you have a large Java codebase with thin unit test coverage and you want generated JUnit tests to use as a scaffold, a regression baseline or a coverage smoke test, and you are prepared to review and prune what it produces. Skip it if you need tests that assert meaningful behaviour, since a generator produces coverage rather than intent, and skip it if your build cannot tolerate a bytecode rewriting agent on the classpath.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It generates tests, it does not write them
Randoop is described in one line as a unit test generator for Java, and it automatically creates unit tests for your classes, in JUnit format. That framing is more precise than it first appears. A generator is not a template engine that fills in a skeleton for you. The word automatically has to mean something, and the way this project achieves it is by running your code and watching what happens. The repository contains two subprojects that exist for that purpose, covered-class and replacecall, and both are described as subprojects for Java agent with load-time bytecode rewriting. A Java agent attached at load time can rewrite the bytecode of your classes as they are loaded, which is the only point at which the tool can see the actual arguments your methods receive, the actual values your constructors are given, and the actual values your getters return, none of which are visible in the source alone. A generated test that asserts a getter returns the value a constructor was given is a test that would have failed to compile if the class had a different shape, and Randoop's job is to find those facts at runtime and write them down as JUnit assertions. The result is coverage expressed as test code, and the value of that depends entirely on what you do with it.
Two agents, and why there are two
The existence of two separate agent subprojects tells you something about the design. The covered-class subproject is the one that records which classes, and which parts of them, were executed, so that the tool knows which methods to try to generate calls for and which branches were actually taken. The replacecall subproject is the one that substitutes calls, which is how the tool explores a method with a deliberately different argument at the moment that argument is used, rather than only at the call site. This split matters for the kind of tests you get out of it. A coverage-only tool can tell you that a getter was called and that it returned something non-null. A tool that can replace a call can determine what a method does when it is given an argument outside the range your own code ever supplies, which is where the interesting boundary behaviour lives. Both agents work at load time, which is also the source of their main practical constraint, since anything that inspects or transforms bytecode, whether for mocking, for coverage, for agents or for instrumentation frameworks, can conflict with the others on the classpath. That is a compatibility question to test in your own build rather than to assume.
The directory layout is the documentation of how it is built
The README explains the directory structure, and for a project of this size the structure is the most informative document. The source directories follow the conventions of the Gradle Java plugin, with each directory holding a java/ subdirectory for Java source and possibly a resources/ subdirectory for other files. The src directory contains the Randoop source code itself, split into main for the code, test for the JUnit tests of Randoop, systemTest for the source of the system tests, testInput for the source of the libraries used in Randoop testing, distribution for the resource files used to create the distribution zip file, docs for the documentation including the manual and resources, and javadoc for the resource files used to create the API documentation. That last grouping is the interesting one. This is a project that produces three distinct published outputs, a library, a manual, and an API reference, and the build keeps the inputs for all three separate from the code. The separation of test and systemTest is the other detail that matters. Unit tests of the generator check the generator. System tests check that the generator, running as a whole against sample libraries, produces what it should. A test tool needs both layers, and a project that keeps them in different source sets is signalling that it takes the distinction seriously.
Gradle, Maven publishing and the local library jar folder
The build is Gradle based, and the repository has the shape of a modern Java project built that way. At the top level there is build.gradle.kts, settings.gradle.kts, a buildSrc/ directory for build logic, a gradle/ directory holding the wrapper, and the gradlew and gradlew.bat launcher scripts. The README is unusually firm about the wrapper directory, marking the gradle folder as the Gradle wrapper directory with a note that it should not be edited, which is a small but useful warning for a contributor who might otherwise tidy it up. The same warning appears implicitly for the lib directory, described as jar files for local copies of libraries not available via Maven, which is the conventional escape hatch for a dependency you cannot get from a public repository. Publishing is handled separately, with a gradle-mvn-push.gradle.kts file for pushing to Maven, distinct from the normal build file, so the release and the local build are kept apart. The scripts directory holds git hook scripts, so the project installs its own hooks on checkout. The remaining tooling files are the interesting part for a contributor, with a .pmd-ruleset.xml for static analysis rules, a .markdownlint-cli2.yaml for the documentation linting, .yamllint.yaml and .yamlfmt.yaml for YAML formatting, a .coderabbit.yaml for an automated code review bot, and a prek.toml for a pre-commit hook runner.
Continuous integration on two services, and a manual that is part of the product
The build is verified on two CI services, with .azure/ for Azure Pipelines and .circleci/ for CircleCI, and a .github/ directory for the GitHub side of things, which usually means issue and pull request templates and workflows. Running the same build on two services is a choice worth reading as intentional for a library with a wide user base, since it tests the build on a matrix of environments rather than one, and a build that only passes on one runner is a build that will break for someone. The documentation is treated as a first-class output, and the project publishes four distinct things, a homepage at randoop.github.io, a manual for users, a developer's manual for people extending the tool, and the Javadoc for the API. The presence of a separate developer manual tells you that extending Randoop is an anticipated activity, which makes sense for a tool whose output quality depends on the checks you write. The manual being linked from the README rather than only from the site also suggests the README is meant to be an entry point rather than a manual, which is a small sign of a project with a mature audience. The documentation source lives in src/docs, and the API documentation source in src/javadoc, both of which are build inputs, so the published artefacts are generated from files under version control alongside the code.
Where generated tests help and where they do not
The honest limitation is the one every test generator has, and it is worth being direct about it. A generated test asserts what the code did, not what the code should do. It will happily record that a method returns null, because that is what happened, and it will not tell you that returning null was a bug. The output is therefore not a substitute for tests written from a specification, and a team that treats a coverage number produced by generated tests as evidence of quality has misunderstood what the tool does. Where generated tests are genuinely valuable is narrower and still substantial. On a legacy codebase, they can produce a broad regression baseline quickly, so that a later refactor has something to fail against. On a class with a large number of getters and setters, they eliminate the boilerplate. In a coverage report, they can reveal branches that were never exercised, because a method with two branches where only one was ever taken is exactly what the coverage agent records. And for a codebase with a legacy test suite that barely runs, a generated suite can turn a broken build into a passing one, which is a real intermediate step. The judgement to make is where in that list your situation sits, because the cost of the wrong answer is a large volume of tests nobody reads.
Licence, releases and the practical adoption questions
Randoop is distributed under the MIT licence, with the licence file at the top level as LICENSE.txt, and a CONTRIBUTING.md alongside the code of conduct expectations implied by the community files in the tree. The MIT terms mean you can use the generated output and the tool in commercial code without obligations, which for a test generator used inside a proprietary codebase is the licence you want. The release history is steady but not fast, with v4.3.4 from 2025-06-06, v4.3.3 from 2024-05-02 and v4.3.2 from 2023-01-08, so roughly one release a year and a half in this list, with the last push to the repository on 2026-10-20 and the repository not archived, which means the branch moves faster than the tags. The practical questions before you adopt it are all about your build rather than about the tool. Randoop needs a Java agent on the classpath to do its work, and if your project already runs another bytecode rewriting agent, a mocking framework with its own agent, or a coverage tool with one, you need to know whether they can coexist. You also need to know which Java version and which JUnit version your project is on, since a generator that emits JUnit 4 assertions is of limited use in a JUnit 5 codebase. And you need to decide in advance where the generated files go, because the default of writing them into your test source tree means they will be committed, reviewed and eventually maintained, and that is a decision about your repository rather than about Randoop.
Editorial conclusion
Adopt Randoop if you have a large Java codebase with thin unit test coverage and you want generated JUnit tests to use as a scaffold, a regression baseline or a coverage smoke test, and you are prepared to review and prune what it produces. Skip it if you need tests that assert meaningful behaviour, since a generator produces coverage rather than intent, and skip it if your build cannot tolerate a bytecode rewriting agent on the classpath. Verify first which Java versions and frameworks your project targets, that the agent is compatible with your build and test runner, and that the generated tests are treated as a starting point rather than as a coverage claim.
Frequently asked questions
What is Randoop and what does it produce?
Randoop is a unit test generator for Java that automatically creates unit tests for your classes in JUnit format. It works by running your code under Java agents that perform load-time bytecode rewriting, so the recorded values come from actual runtime behaviour rather than from reading the source.
How is Randoop built and how do I get it?
The project is built with Gradle, using build.gradle.kts, settings.gradle.kts, a buildSrc directory and the Gradle wrapper, and publishing to Maven is handled separately in gradle-mvn-push.gradle.kts. Documentation, a user manual, a developer manual and the Javadoc are published alongside the project, and the source for all of them lives under src.
What are the covered-class and replacecall subprojects in Randoop?
Both are Java agent subprojects that work through load-time bytecode rewriting. covered-class records which classes and code paths were executed, and replacecall substitutes calls so the tool can explore behaviour with arguments different from those your own code supplies.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/randoop-randoop)Was this useful?