As of DSpace 7 (and above), all new code MUST come with corresponding unit or integration tests.

This guide provides an overview of how to write good unit and integration tests both for the Java (REST API) backend and the Angular (UI) frontend. 


If you are looking for a guide on how to manually test Pull Requests / code, see Testing DSpace 7 Pull Requests.

Backend (Java / REST) Code Tests

Overview of Test Framework

Technologies used

These three modules encompass most of the current test framework:

Checklist for building good tests

Running Tests locally

See the README in our codebase: https://github.com/DSpace/DSpace/#running-tests

Writing Integration Tests

A few quick guidelines on writing DSpace Integration Tests

Writing Unit Tests

A few quick guidelines on writing DSpace Unit Tests

Cleaning up test data

Integration Tests necessarily have to create test data to verify the code they are testing is working properly.  But, just as importantly, they must cleanup any test data they create.  Integration tests which do not cleanup after themselves often result in random or odd CI failures. These odd failures in CI builds may occur anytime the CI environment runs tests in a different order than your local machine and test data from an earlier test directly affects the results of a later test. Keep in mind, JUnit has no defined order of execution for tests. So, if you are seeing tests succeed on your system, but fail in CI (or another system), then it's almost certainly because tests are running in a different order on the two systems...and one order is succeeding while another is failing (likely cause of test data not being cleaned up in prior tests).

Here are three ways to ensure your test data is cleaned up properly in any Integration tests you create. They are roughly prioritized in terms of preference.

  1. Use Builders for automatic cleanup: Whenever possible, use the Builder test classes (see org.dspace.app.rest.builder.*) in "dpace-server-webapp", as these Builder classes automatically cleanup after themselves!

    // Example of creating a test Item via the ItemBuilder class
    // As soon as the method using this "testItem" completes, the "testItem" will be automatically deleted
    // by the AbstractBuilderCleanupUtil (which is called @After every test)
    context.turnOffAuthorisationSystem();
    Item testItem = ItemBuilder.createItem(context, collection);
    context.restoreAuthSystemState();


  2. Cleanup after test POST or file upload: If you are testing a POST command (or file upload), you MUST cleanup the POSTed data by parsing the ID out of the response and using a Builder class for cleanup.  Our best practice is to use the following code logic.  Further examples can be found in the codebase.

    import static com.jayway.jsonpath.JsonPath.read;
    import java.util.concurrent.atomic.AtomicReference;
    
    AtomicReference<UUID> idRef = new AtomicReference<>();
    try {
        // Example of a POST command to create a new Collection while logged in as the user with the given "authToken"
        getClient(authToken).perform(post("/api/core/collections")
                            ...[various params and data sent via POST]...
    
                            // Check the POST was successful, which means we created test content & need to clean it up!
                            .andExpect(status().isCreated())
    
                            // From the JSON response, read the "id" field, parse it as a UUID, and save to "idRef" local variable.
                            .andDo(result -> idRef.set(UUID.fromString(read(result.getResponse().getContentAsString(), "$.id"))));
    } finally {
        // Using the CollectionBuilder, delete the Collection with UUID equal to value of idRef
        CollectionBuilder.deleteCollection(idRef.get());
    }


  3. (If neither of the above are possible) "Manually" delete created data:  If you are creating test data in either the "dspace-api" or "dspace-server-webapp", you should use the Builder method (see above).  This manual test cleanup may no longer be necessary (in v7.x and above) & should be avoided wherever possible. That said, here's an example of manual cleanup:

    // Create test data by temporarily turning off authorization
    context.turnOffAuthorisationSystem();
    WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, true);
    Item item = installItemService.installItem(context, workspaceItem);
    context.restoreAuthSystemState();
    
    [perform various tests]
    
    // Delete the test Item created, again by temporarily turning off authorization
    context.turnOffAuthorisationSystem();
    itemService.delete(context, item);
    context.restoreAuthSystemState();


Changing configuration properties in tests

The DSpace ConfigurationService makes this very easy to do! 

All you have to do is call setProperty  in your test to change the value to whatever value your test needs or expects, for example:

// Change the value of the "dspace.ui.url" to be "http://mydspace.edu"
// NOTE: there are no special permissions required to change values in tests. So, all you need is this one line.
configurationService.setProperty("dspace.ui.url", "http://mydspace.edu");

// Any tests after the above call will see "dspace.ui.url = http://mydspace.edu"
// NOTE: once the test method completes, our test environment will automatically reset "dspace.ui.url" back to the default value.

NOTE: You do NOT need to reset the property value back to the default setting.  After every test runs, the ConfigurationService reloads the defaults from the dspace.cfg  and the local.cfg  used by our test environment.

Frontend (Angular UI) Code Tests

Overview of Test Framework

As the frontend is an Angular.io application (which uses Angular CLI), we follow the best practices for TestingThis includes concentrating our effort on Unit tests (specs) over Integration / end-to-end (e2e) tests per this section of the Angular testing guide. 

Technologies used

Test exists in a few key places in the codebase:

Learning Resources

Checklist for building good tests

Running Tests locally

See the README in our codebase: https://github.com/DSpace/dspace-angular/#testing

Writing Unit (spec) Tests

A few quick guidelines on writing Angular tests using Jasmine:

Writing Integration (e2e) Tests

A few quick guidelines on writing Angular end-to-end (e2e) tests using Cypress: