Skip to content

Commit

Permalink
Merge pull request #1 from sipios/test/add-unit-tests
Browse files Browse the repository at this point in the history
test: add unit tests for DataEventBroadcaster and DataEventListener
  • Loading branch information
phmz authored May 21, 2024
2 parents 4e9dd0d + ddb8276 commit 7eb4735
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 1 deletion.
40 changes: 40 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Test & Coverage
on:
pull_request:
branches:
- '*'

jobs:
test-and-coverage:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'

- name: Set up the Maven dependencies caching
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2

- name: Run tests
run: mvn --batch-mode --update-snapshots verify -Dgpg.skip=true

- name: Add coverage
uses: madrapps/[email protected]
with:
paths: |
${{ github.workspace }}/**/target/site/jacoco/jacoco.xml
token: ${{ secrets.GITHUB_TOKEN }}
title: '### :zap: Coverage report'
update-comment: true
min-coverage-overall: 80
min-coverage-changed-files: 60
continue-on-error: false
33 changes: 32 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

<properties>
<java.version>21</java.version>
<mockito.version>4.11.0</mockito.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -58,6 +59,18 @@
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down Expand Up @@ -122,9 +135,27 @@
<failOnError>false</failOnError>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<scm>
<connection>scm:git:https://github.com/sipios/spring-data-event.git</connection>
<developerConnection>scm:git:[email protected]:sipios/spring-data-event.git</developerConnection>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.sipios.spring.data.event.broadcaster;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.CallbackException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.kafka.core.KafkaTemplate;

public class DataEventBroadcasterTest {
private DataEventBroadcaster broadcaster;
private KafkaTemplate<String, String> kafkaTemplate;
private ObjectMapper objectMapper;

@BeforeEach
void beforeEach() {
kafkaTemplate = mock(KafkaTemplate.class);
objectMapper = new ObjectMapper();
broadcaster = new DataEventBroadcaster(kafkaTemplate, objectMapper);
}

@ParameterizedTest
@CsvSource({
"testEntity.created, testEntity.created",
"'', testentity.created"
})
void testBroadcastEntityCreated(String topicLabel, String expectedTopic) throws Exception {
TestEntity entity = new TestEntity(1, "Test Name", true);
String expectedJson = objectMapper.writeValueAsString(entity);

broadcaster.broadcastEntityCreated(entity, topicLabel);

verify(kafkaTemplate).send(eq(expectedTopic), eq(expectedJson));
}

@ParameterizedTest
@CsvSource({
"testEntity.updated, testEntity.updated",
"'', testentity.updated"
})
void testBroadcastEntityUpdated(String topicLabel, String expectedTopic) throws Exception {
TestEntity entity = new TestEntity(1, "Test Name", false);
String expectedJson = objectMapper.writeValueAsString(entity);

broadcaster.broadcastEntityUpdated(entity, topicLabel);

verify(kafkaTemplate).send(eq(expectedTopic), eq(expectedJson));
}

@ParameterizedTest
@CsvSource({
"testEntity.deleted, testEntity.deleted",
"'', testentity.deleted"
})
void testBroadcastEntityDeleted(String topicLabel, String expectedTopic) throws Exception {
TestEntity entity = new TestEntity(1, "Test Name", true);
String expectedJson = objectMapper.writeValueAsString(entity);

broadcaster.broadcastEntityDeleted(entity, topicLabel);

verify(kafkaTemplate).send(eq(expectedTopic), eq(expectedJson));
}

@Test
void testBroadcastEntityCreatedJsonProcessingException() throws Exception {
objectMapper = mock(ObjectMapper.class);
broadcaster = new DataEventBroadcaster(kafkaTemplate, objectMapper);
TestEntity entity = new TestEntity(1, "Test Name", true);

when(objectMapper.writeValueAsString(entity)).thenThrow(new JsonProcessingException("JSON processing error") {});

assertThrows(CallbackException.class, () -> broadcaster.broadcastEntityCreated(entity, "testEntity.created"));
}

@Test
void testBroadcastEntityUpdatedJsonProcessingException() throws Exception {
objectMapper = mock(ObjectMapper.class);
broadcaster = new DataEventBroadcaster(kafkaTemplate, objectMapper);
TestEntity entity = new TestEntity(1, "Test Name", false);

when(objectMapper.writeValueAsString(entity)).thenThrow(new JsonProcessingException("JSON processing error") {});

assertThrows(CallbackException.class, () -> broadcaster.broadcastEntityUpdated(entity, "testEntity.updated"));
}

@Test
void testBroadcastEntityDeletedJsonProcessingException() throws Exception {
objectMapper = mock(ObjectMapper.class);
broadcaster = new DataEventBroadcaster(kafkaTemplate, objectMapper);
TestEntity entity = new TestEntity(1, "Test Name", true);

when(objectMapper.writeValueAsString(entity)).thenThrow(new JsonProcessingException("JSON processing error") {});

assertThrows(CallbackException.class, () -> broadcaster.broadcastEntityDeleted(entity, "testEntity.deleted"));
}

@Getter
@Setter
@AllArgsConstructor
public static class TestEntity {
private int id;
private String name;
private boolean active;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package com.sipios.spring.data.event.listener;

import com.sipios.spring.data.event.annotation.DataEventEntity;
import com.sipios.spring.data.event.broadcaster.DataEventBroadcaster;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.event.spi.PostDeleteEvent;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostUpdateEvent;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class DataEventListenerTest {
@Mock
private DataEventBroadcaster dataEventBroadcaster;

@InjectMocks
private DataEventListener listener;

@Nested
class AnnotatedEntityTests {

@Test
public void testOnPostInsert() {
PostInsertEvent event = mock(PostInsertEvent.class);
TestEntity entity = new TestEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);

listener.onPostInsert(event);

verify(dataEventBroadcaster).broadcastEntityCreated(entity, "testEntity.created");
}

@Test
public void testOnPostUpdate() {
PostUpdateEvent event = mock(PostUpdateEvent.class);
TestEntity entity = new TestEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);

listener.onPostUpdate(event);

verify(dataEventBroadcaster).broadcastEntityUpdated(entity, "testEntity.updated");
}

@Test
public void testOnPostDelete() {
PostDeleteEvent event = mock(PostDeleteEvent.class);
TestEntity entity = new TestEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);

listener.onPostDelete(event);

verify(dataEventBroadcaster).broadcastEntityDeleted(entity, "testEntity.deleted");
}

@Test
public void testOnPostInsertJsonProcessingException() throws Exception {
PostInsertEvent event = mock(PostInsertEvent.class);
TestEntity entity = new TestEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);
doThrow(new RuntimeException("JSON processing error")).when(dataEventBroadcaster).broadcastEntityCreated(any(), any());

assertThrows(RuntimeException.class, () -> listener.onPostInsert(event));
}

@Test
public void testOnPostUpdateJsonProcessingException() throws Exception {
PostUpdateEvent event = mock(PostUpdateEvent.class);
TestEntity entity = new TestEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);
doThrow(new RuntimeException("JSON processing error")).when(dataEventBroadcaster).broadcastEntityUpdated(any(), any());

assertThrows(RuntimeException.class, () -> listener.onPostUpdate(event));
}

@Test
public void testOnPostDeleteJsonProcessingException() throws Exception {
PostDeleteEvent event = mock(PostDeleteEvent.class);
TestEntity entity = new TestEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);
doThrow(new RuntimeException("JSON processing error")).when(dataEventBroadcaster).broadcastEntityDeleted(any(), any());

assertThrows(RuntimeException.class, () -> listener.onPostDelete(event));
}

@DataEventEntity(creationTopic = "testEntity.created", updateTopic = "testEntity.updated", deletionTopic = "testEntity.deleted")
@Getter
@Setter
@AllArgsConstructor
private static class TestEntity {
private int id;
private String name;
private boolean active;
}
}

@Nested
class NonAnnotatedEntityTests {

@Test
public void testOnPostInsert() {
PostInsertEvent event = mock(PostInsertEvent.class);
NonAnnotatedEntity entity = new NonAnnotatedEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);

listener.onPostInsert(event);

verify(dataEventBroadcaster, never()).broadcastEntityCreated(any(), any());
}

@Test
public void testOnPostUpdate() {
PostUpdateEvent event = mock(PostUpdateEvent.class);
NonAnnotatedEntity entity = new NonAnnotatedEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);

listener.onPostUpdate(event);

verify(dataEventBroadcaster, never()).broadcastEntityUpdated(any(), any());
}

@Test
public void testOnPostDelete() {
PostDeleteEvent event = mock(PostDeleteEvent.class);
NonAnnotatedEntity entity = new NonAnnotatedEntity(1, "Test Name", true);
when(event.getEntity()).thenReturn(entity);

listener.onPostDelete(event);

verify(dataEventBroadcaster, never()).broadcastEntityDeleted(any(), any());
}

@Getter
@Setter
@AllArgsConstructor
private static class NonAnnotatedEntity {
private int id;
private String name;
private boolean active;
}
}
}

0 comments on commit 7eb4735

Please sign in to comment.