Skip to content

Increase code coverage on dynamodb-enhanced module#6700

Closed
andreas-grafenberger wants to merge 21 commits into
aws:masterfrom
anasatirbasa:437-increase_test_coverage
Closed

Increase code coverage on dynamodb-enhanced module#6700
andreas-grafenberger wants to merge 21 commits into
aws:masterfrom
anasatirbasa:437-increase_test_coverage

Conversation

@andreas-grafenberger
Copy link
Copy Markdown
Contributor

@andreas-grafenberger andreas-grafenberger commented Feb 2, 2026

Motivation and Context

The goal of this work is to increase unit, functional, and integration code coverage for the
aws-sdk-java-v2/services-custom/dynamodb-enhanced module.

Initial coverage:

  • Class: 97%
  • Method: 85%
  • Line: 87%
  • Branch: 64%

Target coverage:

  • Class: ≥ 98%
  • Method: ≥ 92%
  • Line: ≥ 92%
  • Branch: ≥ 85%

Achieved coverage:

  • Class: 99%
  • Method: 92%
  • Line: 94%
  • Branch: 91%

These results exceed the defined targets and significantly improve confidence in the correctness and stability of the enhanced DynamoDB module.


Modifications

This pull request expands code coverage across the DynamoDB Enhanced Client by introducing new unit, functional, and integration tests targeting previously uncovered or partially covered code paths.


Testing

  • Existing test suites were executed without regression.
  • New tests were added to specifically target uncovered branches and methods.
  • All new and existing tests pass successfully.
  • Coverage was measured locally after test execution to validate improvements.

Screenshots

Initial coverage:

codeCoverage-before

Achieved coverage:

codeCoverage-after

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@andreas-grafenberger andreas-grafenberger changed the title 437 Increase test coverage Increase test coverage Feb 2, 2026
@anasatirbasa anasatirbasa force-pushed the 437-increase_test_coverage branch from a024740 to fcfbd00 Compare February 10, 2026 17:09
@andreas-grafenberger andreas-grafenberger changed the title Increase test coverage Increase code coverage Feb 10, 2026
@andreas-grafenberger andreas-grafenberger changed the title Increase code coverage Increase code coverage on dynamodb-enhanced module Feb 10, 2026
@anasatirbasa anasatirbasa force-pushed the 437-increase_test_coverage branch from 337c117 to f97adfc Compare February 11, 2026 14:26
@andreas-grafenberger andreas-grafenberger marked this pull request as ready for review February 16, 2026 15:56
@andreas-grafenberger andreas-grafenberger requested a review from a team as a code owner February 16, 2026 15:57
# Conflicts:
#	services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteTableOperationTest.java
# Conflicts:
#	services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/EnhancedClientUtilsTest.java
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;

public final class LogCaptor implements AutoCloseable {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LogCaptor you mention is part of test-utils module, but that module was not added as dependency for dynamodb-enhanced module. Given this small functionality that was needed, I prefered to create a single-class (LogCaptor) instead of importing the entire module (test-utils).

Also, the functionality of the new LogCaptor is manipulating only the targeted logger configuration (adding a new appender and changing the logging level), and doesn't touch the root logger / other loggers configuration (as .../test-utils/.../LogCaptor does).

Another reason is - in the context of .../test-utils/.../LogCaptor, if someone sets any additivity property on false for any monitorized logger, then the tests would fail because the events are not propagated anymore to the root logger (from my point of view, this is a buggy implementation which doesn't allow proper control over logging framework).

To reproduce this buddy behavior - e.g:
Step 1) Go to pom.xml and add dependency to test-utils:

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>test-utils</artifactId>
    <scope>test</scope>
</dependency>

Step 2) Go to class: DefaultAttributeConverterProviderTest.class
and replace:

try (LogCaptor logCaptor = new LogCaptor(DefaultAttributeConverterProvider.class, Level.DEBUG)) {

with:

try (software.amazon.awssdk.testutils.LogCaptor logCaptor =
                 software.amazon.awssdk.testutils.LogCaptor.create(org.apache.logging.log4j.Level.DEBUG)) {

Step 3) Go to services-custom/dynamodb-enhanced/src/test/resources/log4j2.properties and use a custom logger configuration:

logger.defaultAttributeConverterProvider.name = software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider
logger.defaultAttributeConverterProvider.level = warn
logger.defaultAttributeConverterProvider.additivity = false
logger.defaultAttributeConverterProvider.appenderRef.console.ref = ConsoleAppender

.stream()
.flatMap(this::createTestsForInterface)
.collect(toList());
assertEquals(102, dynamicTestList.size());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems brittle; any future interface change breaks this with a confusing failure. Consider "assertThat(...).isNotEmpty()" instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree - this was the purpose, to gain more control over methods that throw UnsupportedOperation and avoid mistakes. Replacing that assertion with assertThat(...).isNotEmpty() makes the test lose its value.

import software.amazon.awssdk.services.dynamodb.model.TableDescription;

@RunWith(Parameterized.class)
public class AnnotatedTableSchemaTest extends LocalDynamoDbSyncTestBase {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there is a lot of duplication between AnnotatedTableSchemaTest (715 lines) and AsyncAnnotatedTableSchemaTest (726 lines). At minimum, can we extract the factory to a shared class?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity;

@RunWith(MockitoJUnitRunner.class)
public class EnhancedClientUtilsTest {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file contains duplicate test pairs:

  • readAndTransformSingleItem_withNullItemMap_returnsNull and readAndTransformSingleItem_nullItemMap_returnsNull — same test, different names
  • readAndTransformSingleItem_withEmptyItemMap_returnsNull and readAndTransformSingleItem_emptyItemMap_returnsNull — same test, different names
  • createKeyFromItem_withPartitionKeyOnly_createsCorrectKey and createKeyFromItem_itemWithPartitionKeyOnly_returnsKeyWithoutSortKey — same test, different na
    mes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that - the cleanup was made in commit: #e547100, thanks!

Comment on lines +30 to +33
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Junit5 is preferred for new test classes https://github.com/aws/aws-sdk-java-v2/blob/master/docs/guidelines/testing-guidelines.md, but I see we are extending existing class that already uses Junit4, so this is probably fine

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I would keep it as it is.
The reason I used Junit4 is related to the class parameterization (instead of method parameterization from Junit 5).
As you already noticed, the base class LocalDynamoDbTestBase already uses Junit4 and mixing both versions of Junit (4 and 5) is causing troubles in some cases, just an example: when using after / before behavior.

Comment on lines +19 to +21
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I performed a quick check through all modified classes and addressed this suggestion - see commit: 87a6083. The commit contains only this kind of refactoring (including for existing tests from modified classes).

Comment on lines +285 to +295
public void builder_startAtValueIsLessThanMinusOne_throwsIllegalArgumentException() {
assertThrows(IllegalArgumentException.class,
() -> VersionedRecordExtension.builder().startAt(-2L).build(),
"startAt must be -1 or greater");
}

@Test
public void builder_incrementByValueIsLessThanOne_throwsIllegalArgumentException() {
assertThrows(IllegalArgumentException.class,
() -> VersionedRecordExtension.builder().incrementBy(0L).build(),
"incrementBy must be greater than 0.");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use parameterized tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;

public class VersionedRecordExtensionTest extends LocalDynamoDbSyncTestBase {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use ParameterizedTest for versionAttribute_withInvalid* tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

@Test
public void generateRequest_mergesKeysAndAttributes_incompatibleConsistentRead_throws() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, it'd be great if we can use ParameterizedTests

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented some parameterization, please see commit: #386e270, modified class:

@zoewangg
Copy link
Copy Markdown
Contributor

Closing in favor of #6969

@zoewangg zoewangg closed this May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants