Web Solutions

Testing in Java Like a Pro: JUnit, Cucumber, Logging & Debugging

·

·

As a seasoned Java software engineer, writing code is only half the job — testing, logging, and debugging are equally crucial to building production-grade systems. Whether you’re writing a simple REST API or orchestrating microservices, robust testing and clear logs can be the difference between a smooth deploy and a 3 AM incident.

In this post, we’ll cover:

  • ✅ Writing unit & integration tests using JUnit 5
  • ✅ Creating behavior-driven tests with Cucumber
  • ✅ Adding meaningful logging with SLF4J + Logback
  • ✅ Debugging effectively in modern Java projects

🧪 1. Unit Testing with JUnit 5

🛠️ Why Use JUnit?

JUnit is the standard unit testing framework for Java. It’s fast, supports parameterized tests, and integrates with all major build tools (Maven/Gradle) and CI platforms (GitHub Actions, Jenkins).

📄 Sample Test

class Calculator {
public int add(int a, int b) {
return a + b;
}
}

class CalculatorTest {

private Calculator calculator;

@BeforeEach
void setup() {
calculator = new Calculator();
}

@Test
void shouldAddTwoNumbers() {
Assertions.assertEquals(5, calculator.add(2, 3));
}
}

🧠 Pro Tips:

  • Use @BeforeEach for setup logic
  • Structure tests into given/when/then comments
  • Use AssertJ for better readability: assertThat(result).isEqualTo(5);

🌱 2. Behavior-Driven Testing with Cucumber

Cucumber lets you write tests in plain English (.feature files), making tests readable by QA, PMs, and non-dev stakeholders. It’s great for acceptance testing and complex business logic.

📄 Sample Feature File

Feature: Addition
Scenario: Add two numbers
Given the numbers 4 and 6
When I add them
Then the result should be 10

🧪 Step Definitions

public class StepDefinitions {

private int a, b, result;

@Given("the numbers {int} and {int}")
public void givenNumbers(int num1, int num2) {
a = num1;
b = num2;
}

@When("I add them")
public void addThem() {
result = a + b;
}

@Then("the result should be {int}")
public void verifyResult(int expected) {
Assertions.assertEquals(expected, result);
}
}

🧠 Pro Tips:

  • Use Cucumber only when business logic benefits from natural-language testing
  • Keep step definitions clean and reusable
  • Run Cucumber tests with Maven/Gradle plugins or JUnit runners

📄 3. Logging Best Practices (SLF4J + Logback)

Logging is vital for understanding app behavior in dev and production.

✅ Use SLF4J for Logging

It’s the standard facade for Java logging frameworks.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);

public void registerUser(String username) {
logger.info("Registering user: {}", username);
// do something
logger.debug("Completed DB transaction for user: {}", username);
}
}

🧠 Pro Tips:

  • Use info for high-level actions, debug for dev-only details, warn/error for issues
  • Avoid string concatenation ("User: " + name) — use {} placeholders
  • Configure Logback via logback-spring.xml for log levels, formats, rotation

🐞 4. Debugging Like a Pro

Modern IDEs like IntelliJ make debugging easier than ever.

🧰 How to Debug Java Efficiently:

  • Use breakpoints and run in debug mode
  • Set conditional breakpoints for filtering (userId == 5)
  • Use Evaluate Expression to inspect or test code changes live
  • Add logpoints (non-intrusive logs during debugging)
  • Analyze stack traces and thread dumps for concurrency issues

🔥 Pro Debugging Tips:

  • Use @Slf4j from Lombok for cleaner logging injection
  • For integration debugging, use Postman + logs + breakpoints
  • For Spring Boot, enable: logging.level.org.springframework=DEBUG

✅ Final Thoughts

Testing, logging, and debugging are not afterthoughts — they are core engineering skills that separate average devs from professionals.

  • Write unit tests with JUnit for core logic
  • Use Cucumber where business logic needs to be verified in plain language
  • Keep your logs meaningful and consistent
  • Debug with intention and tools — not print statements

Master these practices, and you’ll not only ship fewer bugs — you’ll also debug and fix them faster when they inevitably arise.


Leave a Reply

Your email address will not be published. Required fields are marked *