Skip to content

feat: Add assertj-protobuf module#3957

Open
belljun3395 wants to merge 10 commits intoassertj:mainfrom
belljun3395:feature/assertj-protobuf-3736
Open

feat: Add assertj-protobuf module#3957
belljun3395 wants to merge 10 commits intoassertj:mainfrom
belljun3395:feature/assertj-protobuf-3736

Conversation

@belljun3395
Copy link
Contributor

@belljun3395 belljun3395 commented Oct 1, 2025

AssertJ Protobuf Module Implementation

Implemented Features

A new Maven module providing:

Main Classes

org.assertj.protobuf.api.Assertions

  • Entry point for AssertJ Protobuf
  • Provides assertThat(Message) static method

org.assertj.protobuf.api.MessageAssert<T extends Message>

  • Main assertion class for Protobuf messages
  • Extends AbstractAssert following AssertJ standards

org.assertj.protobuf.internal.MessageDifferencer

  • Internal message comparison logic
  • Supports repeated fields, nested messages, field exclusion, etc.

Provided Methods

// Basic comparison
assertThat(actual).isEqualTo(expected);

// Ignore repeated field order
assertThat(actual).ignoringRepeatedFieldOrder().isEqualTo(expected);

// Exclude specific fields
assertThat(actual).ignoringFields("timestamp").isEqualTo(expected);

// Partial comparison (only expected fields)
assertThat(actual).comparingExpectedFieldsOnly().isEqualTo(expected);

// Field presence checks
assertThat(actual).hasField("name");
assertThat(actual).doesNotHaveField("deletedAt");

Dependency Management

<!-- Compile -->
<dependency>
  <groupId>org.assertj</groupId>
  <artifactId>assertj-core</artifactId>
  <version>${project.version}</version>
</dependency>

<!-- Provided - users choose version -->
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>4.29.3</version>
  <scope>provided</scope>
</dependency>

Core Implementation Logic

Repeated Field Handling

Protobuf's repeated fields don't support hasField(), requiring special handling:

if (field.isRepeated()) {
  // Use getField() instead of hasField()
  actualValue = actual.getField(field);
  expectedValue = expected.getField(field);
  
  // Treat empty lists as null
  List<Object> actualList = (List<Object>) actualValue;
  if (actualList.isEmpty()) actualValue = null;
}

AS_SET Mode (Order-Insensitive)

Algorithm for comparing repeated fields like sets:

  1. For each item in expected list
  2. Find matching item in actual list
  3. Remove matched item from actual list (prevent duplicates)
  4. Success if all items matched

Recursive Message Comparison

Nested messages are compared recursively, tracking field paths:

  • "field_name""nested.field_name""nested.child.field_name"

Usage Examples

Basic Usage

import static org.assertj.protobuf.api.Assertions.assertThat;

@Test
void should_compare_protobuf_messages() {
  // GIVEN
  UserProto expected = UserProto.newBuilder()
      .setName("John")
      .setAge(30)
      .build();
  
  UserProto actual = userService.getUser(userId);
  
  // WHEN/THEN
  assertThat(actual).isEqualTo(expected);
}

Advanced Patterns

@Test
void should_ignore_timestamp_and_repeated_order() {
  // GIVEN
  OrderProto expected = OrderProto.newBuilder()
      .setOrderId("ORD-123")
      .addItems("ITEM-1")
      .addItems("ITEM-2")
      .build();
  
  OrderProto actual = orderService.getOrder("ORD-123");
  
  // WHEN/THEN
  assertThat(actual)
      .ignoringFields("createdAt", "updatedAt")
      .ignoringRepeatedFieldOrder()
      .isEqualTo(expected);
}

Build & Test

Build

# Build protobuf module only
./mvnw clean install -pl assertj-protobuf

# Include tests
./mvnw clean install -pl assertj-protobuf,assertj-tests/assertj-integration-tests/assertj-protobuf-tests

Run Tests

./mvnw test -pl assertj-tests/assertj-integration-tests/assertj-protobuf-tests

@scordio scordio force-pushed the main branch 2 times, most recently from b2b071f to 2dab02c Compare November 8, 2025 18:05
@scordio scordio changed the title feat: Add assertj-protobuf module #3736 feat: Add assertj-protobuf module Nov 15, 2025
@scordio scordio changed the title feat: Add assertj-protobuf module feat: Add assertj-protobuf module Nov 15, 2025
@scordio scordio added this to the 3.28.0 milestone Nov 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add assertj-protobuf to assertj ecosystem.

2 participants