DEV Community

Cover image for Getting Started with Java Integration Testing using JUnit 4 and DBUnit Datasets
Agaba Derrick Junior
Agaba Derrick Junior

Posted on

Getting Started with Java Integration Testing using JUnit 4 and DBUnit Datasets

“Mocking is cool—until it lies to you.”
If you’ve ever mocked your way through a test only to get blindsided in production, welcome to the club. That’s exactly why I started relying on real integration tests using datasets in Java.

Why not unit tests, why integration tests?
Unit tests are fast and focused but don’t touch the real database, objects, or constraints. Integration tests simulate the real thing — they boot your application context, load real data, and let you test how your code behaves in production-like conditions.

Here’s a stripped-down version of how my test class usually looks:

`@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppTestConfig.class)
@Transactional
public class SampleServiceTest extends BaseWebContextSensitiveTest {

    @Before
    public void setupDataset() throws Exception {
        executeDataSetWithStateManagement("testdata/sample.xml");
    }

    @Test
    public void testSaveSample() throws Exception {
        Sample sample = new Sample();
        sample.setName("Test Sample");
        sample.setStatus("Pending");

        sampleService.save(sample);

        Sample result = sampleService.fetchById(sample.getId());
        assertEquals("Test Sample", result.getName());
    }
}

Enter fullscreen mode Exit fullscreen mode

What’s in the Dataset?

The sample.xml The file is a snapshot of database rows. Here's what a minimal DBUnit dataset looks like:

<dataset>
    <sample id="1" name="Existing Sample" status="Approved"/>
</dataset>
Enter fullscreen mode Exit fullscreen mode

This gets loaded into the test database before each test. It makes your test repeatable and independent of whatever is in the database.
Common Lessons

Here are a few things I’ve learned the hard way:

Make datasets small. Load only what’s needed.
Assert the DB state. Don’t just trust return values — fetch the record and check it.
Use @Transactional With rollback to avoid polluting your test DB.
Don’t mix unit tests with integration tests. Separate them for clarity and speed.

Do you know what the best part is?

If something breaks, like a foreign key violation or bad insert, it breaks for real. That’s what you want in a test. If all your tests pass, but nothing works in staging, that’s a red flag that your mocks lied to you

If you’re working in a legacy codebase or an enterprise app like OpenELIS, you’ll often run into weird behavior caused by data inconsistencies, cascading updates, or transactional issues. Mocking won’t catch that. Real data will.

** Next up, I’ll be writing about: **

  • How to deal with circular foreign keys in datasets
  • Testing update and delete scenarios with DBUnit
  • Making your test data realistic but minimal

Written by Agaba Derrick, an open-source software engineer passionate about reliable backend systems and breaking things the right way.
Follow me on GitHub

java #integrationtests #javadevelopers

Top comments (0)