Looking to create your first tests in a Java project, but not sure where to start? You’ve come to the right place.
In this guide, we’ll explain how you can get started with Java testing, showing you where to focus your efforts for maximum impact and providing framework recommendations for different project types.
Reasons to start testing in Java
If you’re looking to incorporate testing into your Java project, you’ll likely need to explain the benefits of doing so to your team. To help you along, here’s a refresher on why testing in Java is useful in the first place.
The key reason for testing software is to create confidence for those using and operating the finished application. For users, a piece of Java software that’s well-tested means a consistent experience, as well as fewer bugs and things unexpectedly breaking. For those operating your application, which can be your team or someone in a dedicated technical operations role, a well-tested Java app will lead to fewer unforeseen critical issues that can destroy someone’s weekend plans.
In addition to these direct benefits, a side effect of writing tests is that the process requires developers to write software in a way that’s testable. If you’re working on a Java project with a strong testing culture, you’re less likely to create functions and classes that are overly complex. When you encounter difficulty in writing a test, that’s a sign that you need to break down the functionality you’re developing into more understandable, tractable pieces.
Tests are also a way to give your team some guardrails in terms of coding style. When you set up unit tests, for example, using JUnit, you create examples of how source files and test files should be structured. When you create API tests with REST-assured, you set up expectations on where API methods go and what code can be shared between API endpoints. If you expect other developers to join the project later, having good tests can quickly get them up to speed on your coding style. A project that’s well-tested is more attractive for Java developers precisely because it’s easier to get started on, and because it’s easier to make changes to the code.
Having covered the general rationale for testing, let’s now dive into the specifics of getting started with testing in Java.
Analysis paralysis and testing in Java
Java developers naturally want the best possible framework when getting started with testing. With so many options available, it’s easy to get stuck on the ‘choosing the right framework’ step.
Be wary of this common pitfall, simply because there’s no such thing as a perfect option! It’ll be difficult to know your project’s needs and how these might look in the future, all before you start working on your test suite.
Instead, our recommended approach is to spend as little time as possible on choosing a framework and more time actually working on tests. Start with an option that’s widely accepted in the Java ecosystem, like JUnit. It’s the default choice for many Java projects, so there are good docs and many examples available online. JUnit will likely covered most of your use cases, and if you need to move to a different framework down the line, you’ll likely find sufficient resources on migrating to a new framework—again, simply because basic frameworks like JUnit are so common.
Going from zero unit tests to one unit test is hard. Don’t make that process more difficult than it needs to be by trying to pick the perfect testing tool. Focus instead on writing the best tests possible!
Use the test pyramid to focus your Java testing efforts
To quickly make good progress on adding Java tests to your project, consider the concept of a test pyramid. A testing best practice is to have multiple layers of tests in different quantities. The pyramid commonly ends up with many unit tests, some integration or service tests, and a few end-to-end tests. Here’s how we use the test pyramid to help us plan out the work on adding tests to our codebase.
Building a test pyramid for new projects It’s no coincidence that unit tests make up the pyramid’s base. Because unit tests help you shape both the project’s coding style and the codebase’s layout, you’re best off starting with the unit testing layer when working on a new project. Unit tests are fast to run and provide quick feedback even in the absence of end-to-end functionality. Having unit tests will facilitate adding other kinds of tests later, since you’ll already know where to put test files, how tests get run, and what functions go into test helpers.
Structuring a test pyramid for legacy projects Legacy codebases, such as older products that still have many customers using them daily, frequently lack unit tests. Writing new unit tests in such projects can be unfeasible—the code might have a convoluted structure with many side effects. Adding beneficial unit tests to such codebases will require rewriting parts of the code from scratch. And if you start with a rewrite, it’s going to be tricky to test the result.
If you’re tasked with adding tests to a legacy codebase, consider first building guardrails by writing end-to-end tests. Having automated end-to-end testing in place will let you rewrite and refactor more confidently, allowing you to later add other types of tests without sacrificing your end users’ experience in the short-term.
For end-to-end tests on legacy projects, we have two recommendations:
- If your team is backend-focused with a preference for Java, start with Selenium WebDriver. This is a common option in the Java ecosystem and will meet most requirements for the majority of legacy systems.
- If your team is full-stack, consider Cypress. Cypress tests are written in JavaScript rather than Java, but if your team is full-stack it’s likely to already have some JavaScript experience. Cypress is easier to use compared to Selenium WebDriver, but of course requires familiarity with JavaScript.
Prioritise API and integration tests for API-based projects For projects that interact with other parts of your environment through APIs, we advise starting with API tests. The API is a type of contract between your service and other services, and it’s important to not break that contract. And if you meet the contract, you have discretion to make changes to the code powering the API.
By starting with API tests in such projects, you ensure that everyone that relies on your service can continue using it as you start rewriting your code to add unit tests. A simple framework for API tests is REST-assured, provided that you’re building a RESTful API.
Get started with Java testing today
Here’s a summary of our tips on getting started with Java testing:
- Don’t spend too much time choosing the ‘perfect’ testing framework; go with one of the standard options in the ecosystem.
- Focus on the right test type to maximise the effectiveness of testing for your particular project. We advise prioritising unit tests for new projects, end-to-end tests for legacy products, and API tests for services.
If you’re ready to start testing email-related functionality in your Java application, check out Mailosaur.
We provide a Java library that you can combine with JUnit, REST-assured, Selenium WebDriver and other Java tools to automate the testing of transactional emails in your application. If you decide to go with Cypress, we have a library for that, also.