Why Skipping Unit Tests Costs More: Java and Groovy Examples

The article explains why many developers avoid unit testing despite its importance, demonstrates a Java method for filtering unpromised tools in a home‑renovation app, provides complete JUnit and Groovy/Spock test implementations, and shows how richer output from Groovy/Spock can speed debugging.

FunTester
FunTester
FunTester
Why Skipping Unit Tests Costs More: Java and Groovy Examples

Background

Most programmers have heard of unit testing and consider it essential, yet many still claim they lack time, arguing that writing tests adds about 20% overhead to development.

Practical Scenario

The author designs a prototype for a home‑renovation registry where users share material and tool information. The core functionality is a method that returns a list of tools that have not been promised.

public List<Tool> neededToolList(Project project) {
    final List<Tool> retList = new ArrayList<>();
    if (project.getTools() == null || project.getTools().isEmpty()) {
        return retList;
    }
    for (Tool tool : project.getTools()) {
        if (!tool.getPromise().isPromised()) {
            retList.add(tool);
        }
    }
    List<Tool> tools = lookupService.updateToolList(retList);
    return tools;
}

JUnit Test Example

A single JUnit test creates a project with two tools, mocks the LookupService to return a price for the unpromised tool, invokes neededToolList, and asserts that only one tool is returned with the expected price.

@Test
public void testNeededToolList() {
    Tools _instance = new Tools();
    Project project = new Project();
    Promise promise = new Promise();
    promise.setProject(project);
    promise.setPromised(false);
    Promise promise2 = new Promise();
    promise2.setProject(project);
    promise2.setPromised(true);
    List<Tool> tools = new ArrayList<>();
    List<Tool> lookupTools = new ArrayList<>();
    Tool tool1 = new Tool();
    tool1.setName("table saw");
    tool1.setStoreId("T001");
    tool1.setPromise(promise);
    tools.add(tool1);
    lookupTools.add(tool1);
    Tool tool2 = new Tool();
    tool2.setName("pneumatic nail guns");
    tool2.setStoreId("T027");
    tool2.setPromise(promise2);
    tools.add(tool2);
    project.setTools(tools);
    List<Tool> mockedTools = new ArrayList<>();
    Tool mockedTool1 = new Tool();
    mockedTool1.setPromise(promise);
    mockedTool1.setName("table saw");
    mockedTool1.setStoreId("T001");
    mockedTool1.setPrice(129.0);
    mockedTools.add(mockedTool1);
    lookupService = Mockito.mock(LookupServiceImpl.class);
    Mockito.when(lookupService.updateToolList(lookupTools)).thenReturn(mockedTools);
    _instance.setLookupService(lookupService);
    List<Tool> returnedTools = _instance.neededToolList(project);
    assertTrue(returnedTools.size() == 1);
    for (Tool tool : returnedTools) {
        assertEquals(129.0, tool.getPrice(), 0.01);
    }
}

Groovy Test Version

The same logic is rewritten in Groovy, taking advantage of Groovy’s map‑to‑object conversion and concise syntax.

class GroovyToolsTest extends GroovyTestCase {
    def lookupService = [
        updateToolList : { List<Tool> toolList ->
            toolList.each {
                if (it.storeId == "T001") {
                    it.price = 129.0
                }
            }
            return toolList
        }
    ] as LookupService

    void testNeededToolList() {
        def _instance = new Tools()
        def project = new Project()
        project.tools = [
            new Tool(name: "table saw", storeId: "T001", promise: new Promise(project: project, promised: false)),
            new Tool(name: "pneumatic nail guns", storeId: "T027", promise: new Promise(project: project, promised: true))
        ]
        _instance.lookupService = lookupService
        def returnedList = _instance.neededToolList(project)
        assert returnedList.size() == 1
        returnedList.each {
            if (it.storeId == "T001") {
                assert it.price == 129.0
            }
        }
    }
}

Spock Specification

Using the Spock framework, the test becomes more behavior‑driven while reusing the same mock service.

class ToolsSpec extends Specification {
    def lookupService = [
        updateToolList : { List<Tool> toolList ->
            println "mocked service"
            toolList.each { tool ->
                if (tool.storeId == "T001")
                    tool.price = 129.0
            }
            return toolList
        }
    ] as LookupService

    def "Lookup needed tool list"() {
        given:"Create instance"
        def _instance = new Tools()
        def project = new Project()
        project.tools = [
            [name: "table saw", storeId: "T001", promise: [project: project, promised: false] as Promise] as Tool,
            [name: "pneumatic nail guns", storeId: "T027", promise: [project: project, promised: true] as Promise] as Tool
        ] as List<Tool>
        _instance.lookupService = lookupService
        expect:"Tool List"
        def returnedList = _instance.neededToolList(project)
        returnedList.size() == 1
        returnedList.each {
            if (it.storeId == "T001") {
                assert it.price == 129.0
            }
        }
    }
}

Output Comparison

JUnit’s failure message shows only the expected and actual values, while Groovy/Spock provide a detailed assertion trace that includes the offending object and its field values, making debugging faster.

java.lang.AssertionError: expected:<128.0> but was:<129.0>
    ...
Assertion failed:
assert it.price == 128.0
       |  |     |
       |  129.0 false
org.projectregistry.model.Tool@5e59238b
    at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:399)
    ...

Conclusion

The author encourages developers to try Groovy and Spock because they reduce boilerplate, produce clearer test failures, and make unit testing more enjoyable, especially when time constraints discourage writing tests.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaunit testingJUnitMockitoGroovySpock
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.