Igor's Techno Club

When Writing Tests Use Meaningful Data

When writing unit tests, it's easy to fall into the trap of using arbitrary values for your test variables. However, using meaningful, human-readable values can significantly improve the readability and maintainability of your tests. In this post, we'll explore why this practice is important and provide some examples of good and bad variable usage in test cases.

Why Use Human-Readable Values?

  1. Improved Readability: Tests with meaningful values are easier to understand at a glance.
  2. Better Debugging: When a test fails, human-readable values make it easier to identify the issue.
  3. Closer to Real-World Scenarios: Using values similar to those in production helps catch potential real-world issues.
  4. Self-Documenting Code: Meaningful values serve as documentation, reducing the need for comments.

Examples

Let's look at some examples using Java and JUnit to illustrate the difference between poor and good variable usage in tests.

Example 1: Customer ID

Typical Example:

@Test
public void testCustomerPurchase() {
    Customer customer = new Customer(42);
    Order order = new Order(101);
    assertTrue(customer.canPurchase(order));
}

Better Example:

@Test
public void testCustomerPurchase() {
    Customer customer = new Customer(1000001);  // Typical 7-digit customer ID
    Order order = new Order("ORD-2023-06-15-001");  // Order ID with date
    assertTrue(customer.canPurchase(order));
}

In this example, ORD-2023-06-15-001 represents a value that has the same format as in the production system. So the next time you see similar value in the logs, application code or other places, you can guess that it might be an order ID

Example 2: Product Pricing

Typical Example:

@Test
public void testProductDiscount() {
    Product product = new Product("Item", 10);
    assertEquals(8, product.applyDiscount(20));
}

Better Version:

@Test
public void testProductDiscount() {
    Product product = new Product("Leather Wallet", 49.99);
    assertEquals(39.99, product.applyDiscount(20), 0.01);
}

This example uses a realistic product name and price, making the test more relatable to real-world scenarios. It also uses a delta value in the assertion to account for potential floating-point inaccuracies, which will most likely be the case in real life. When it comes to testing prices, remember to handle big values as well, depending on your field domain area: if it's real estate, I can imagine having an item with a price of 1 billion dollars.

Example 3: Date and Time

Typical Example:

@Test
public void testAppointmentScheduling() {
    String appointmentTime = "2024-01-01-11-01";
    assertTrue(scheduler.isAvailable(appointmentTime));
}

Better Version:

@Test
public void testAppointmentScheduling() {
    String appointmentTime = "2024-01-27-22-10";
    assertTrue(scheduler.isAvailable(appointmentTime));
}

Dealing with dates and timezones is tricky, but what is even more complex is reading a pull request with tests covering it. If it doesn't matter which date value to choose, use the one whose format can be easier to identify: "2024-01-27-22-10" here gives us hints about the order of year, month, day, etc., so there's no need to look at the time parsing logic.

Conclusion

Using human-readable and meaningful values in your test variables can significantly improve the quality and maintainability of your test suite. By making your tests more realistic and easier to understand, you're not only making life easier for yourself and your team members but also increasing the likelihood of catching real-world issues before they make it to production.

Remember, the goal is to create tests that are as close to real-world scenarios as possible while still being easy to read and understand. By following this practice, you'll create a more robust and maintainable test suite that truly adds value to your development process.

#testing