Created
March 3, 2026 13:54
-
-
Save musketyr/f491e099baf719f0b9f78201e78e4950 to your computer and use it in GitHub Desktop.
Spock → JUnit 5 Migration Diff: RoiNotificationServiceSpec (sc185896)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Spock → JUnit 5 Migration: RoiNotificationServiceSpec</title> | |
| <style> | |
| * { box-sizing: border-box; margin: 0; padding: 0; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; padding: 20px; line-height: 1.6; } | |
| h1 { text-align: center; margin-bottom: 20px; color: #333; } | |
| .section { background: white; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); overflow: hidden; } | |
| .section-header { background: #2d3748; color: white; padding: 12px 16px; cursor: pointer; display: flex; justify-content: space-between; align-items: center; } | |
| .section-header:hover { background: #4a5568; } | |
| .section-header h2 { font-size: 16px; font-weight: 600; } | |
| .section-header .toggle { font-size: 12px; } | |
| .section-content { display: block; } | |
| .section-content.collapsed { display: none; } | |
| .diff-container { display: grid; grid-template-columns: 1fr 1fr; } | |
| .diff-panel { padding: 16px; overflow-x: auto; } | |
| .diff-panel.left { background: #fff5f5; border-right: 1px solid #e2e8f0; } | |
| .diff-panel.right { background: #f0fff4; } | |
| .diff-panel h3 { font-size: 12px; text-transform: uppercase; color: #718096; margin-bottom: 12px; letter-spacing: 0.5px; } | |
| pre { font-family: 'SF Mono', Monaco, 'Courier New', monospace; font-size: 13px; white-space: pre-wrap; word-wrap: break-word; } | |
| .left pre { color: #c53030; } | |
| .right pre { color: #276749; } | |
| .summary { background: #c6f6d5; border-left: 4px solid #38a169; padding: 12px 16px; margin: 0; } | |
| .summary p { color: #276749; font-size: 14px; } | |
| .summary strong { color: #22543d; } | |
| @media (max-width: 768px) { .diff-container { grid-template-columns: 1fr; } .diff-panel.left { border-right: none; border-bottom: 1px solid #e2e8f0; } } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>🦀 Spock → JUnit 5 Migration: RoiNotificationServiceSpec</h1> | |
| <p style="text-align: center; color: #666; margin-bottom: 20px;">Story: <a href="https://app.shortcut.com/agorapulse/story/185896">sc185896</a> | PR: <a href="https://github.com/agorapulse/platform/pull/73550">#73550</a></p> | |
| <!-- Section: Imports --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>📦 Imports</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>package agorapulse.roi.notification | |
| import agorapulse.commons.messagesource.interpolation.InterpolatingMessageSource | |
| import agorapulse.notification.sender.NotificationSender | |
| import agorapulse.organization.client.internal.OrganizationClient | |
| import agorapulse.organization.client.model.ManagerSummary | |
| import agorapulse.organization.client.model.OrganizationManagerSummary | |
| import agorapulse.organization.client.model.OrganizationSummary | |
| import agorapulse.roi.core.models.export.RoiEmailParameters | |
| import agorapulse.roi.core.models.parameters.RoiExportParametersBuilder | |
| import com.agorapulse.security.jwt.JsonWebTokenService | |
| import spock.lang.Specification | |
| import java.time.LocalDate</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>package agorapulse.roi.notification; | |
| import agorapulse.commons.messagesource.interpolation.InterpolatingMessageSource; | |
| import agorapulse.notification.sender.NotificationSender; | |
| import agorapulse.notification.templates.NotificationTemplateBundle; | |
| import agorapulse.organization.client.internal.OrganizationClient; | |
| import agorapulse.organization.client.model.ManagerSummary; | |
| import agorapulse.organization.client.model.OrganizationManagerSummary; | |
| import agorapulse.organization.client.model.OrganizationSummary; | |
| import agorapulse.roi.core.models.export.RoiEmailParameters; | |
| import agorapulse.roi.core.models.parameters.RoiExportParametersBuilder; | |
| import com.agorapulse.security.jwt.JsonWebTokenService; | |
| import org.junit.jupiter.api.BeforeEach; | |
| import org.junit.jupiter.api.Test; | |
| import org.junit.jupiter.api.extension.ExtendWith; | |
| import org.mockito.Mock; | |
| import org.mockito.junit.jupiter.MockitoExtension; | |
| import java.io.File; | |
| import java.time.LocalDate; | |
| import java.util.List; | |
| import java.util.Locale; | |
| import java.util.Map; | |
| import java.util.function.Consumer; | |
| import static org.assertj.core.api.Assertions.assertThat; | |
| import static org.mockito.ArgumentMatchers.any; | |
| import static org.mockito.ArgumentMatchers.anyMap; | |
| import static org.mockito.Mockito.never; | |
| import static org.mockito.Mockito.verify; | |
| import static org.mockito.Mockito.when;</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Added JUnit 5 annotations (@Test, @BeforeEach, @ExtendWith). Replaced Spock mocking with Mockito (@Mock, MockitoExtension). Added AssertJ assertions. Added explicit Java imports for List, Map, Locale, Consumer, File.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Class & Fields --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🏗️ Class & Fields</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>class RoiNotificationServiceSpec extends Specification { | |
| RoiNotificationService roiNotificationService | |
| InterpolatingMessageSource interpolatingMessageSource = Mock(InterpolatingMessageSource) | |
| JsonWebTokenService tokenService = Mock(JsonWebTokenService) | |
| NotificationSender notificationSender | |
| OrganizationClient organizationClient = Mock(OrganizationClient)</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@ExtendWith(MockitoExtension.class) | |
| class RoiNotificationServiceTest { | |
| @Mock | |
| private InterpolatingMessageSource interpolatingMessageSource; | |
| @Mock | |
| private JsonWebTokenService tokenService; | |
| @Mock | |
| private NotificationSender notificationSender; | |
| @Mock | |
| private OrganizationClient organizationClient; | |
| private RoiNotificationService roiNotificationService;</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced "extends Specification" with @ExtendWith(MockitoExtension.class). Replaced Spock Mock() inline initialization with @Mock annotations. Added explicit private visibility and semicolons.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Setup --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🔧 Setup</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void setup() { | |
| tokenService = Mock(JsonWebTokenService) | |
| notificationSender = Mock(NotificationSender) | |
| organizationClient = Mock(OrganizationClient) | |
| roiNotificationService = new RoiNotificationService('bucket', | |
| interpolatingMessageSource, | |
| tokenService, | |
| notificationSender, | |
| organizationClient, | |
| 'url' | |
| ) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@BeforeEach | |
| void setUp() { | |
| roiNotificationService = new RoiNotificationService( | |
| "bucket", | |
| interpolatingMessageSource, | |
| tokenService, | |
| notificationSender, | |
| organizationClient, | |
| "url" | |
| ); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Spock setup() with @BeforeEach setUp(). Removed redundant mock re-initialization (handled by @Mock). Changed single quotes to double quotes for Java strings.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 1 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 should not send notification if no recipient</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should not send notification if no recipient'() { | |
| given: | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters() | |
| roiEmailParameters.mimeType = 'mime' | |
| roiEmailParameters.roiExportParameters = new RoiExportParametersBuilder( | |
| '1', new ManagerSummary(identityId: '38'), LocalDate.now(), | |
| LocalDate.now(), 1, '2', 3).build() | |
| when: | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| [:], null, roiEmailParameters) | |
| then: | |
| !value | |
| 0 * notificationSender.send(_) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void shouldNotSendNotificationIfNoRecipient() { | |
| // given | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters(); | |
| roiEmailParameters.setMimeType("mime"); | |
| ManagerSummary manager = new ManagerSummary(); | |
| manager.setIdentityId("38"); | |
| roiEmailParameters.setRoiExportParameters( | |
| new RoiExportParametersBuilder("1", manager, LocalDate.now(), | |
| LocalDate.now(), 1L, "2", 3L).build() | |
| ); | |
| // when | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| Map.of(), null, roiEmailParameters); | |
| // then | |
| assertThat(value).isFalse(); | |
| verify(notificationSender, never()).send( | |
| any(NotificationTemplateBundle.class), anyMap(), any(Consumer.class)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Added @Test annotation. Replaced Groovy property access with Java setters. Replaced Groovy map constructor syntax with explicit setter calls. Replaced [:] with Map.of(). Replaced Spock !value with AssertJ assertThat().isFalse(). Replaced 0 * mock.method() with verify(mock, never()).method().</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 2 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 should not send notification if recipient id is not in org manager ids</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should not send notification if recipient id is not in org manager ids'() { | |
| given: | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters() | |
| roiEmailParameters.mimeType = 'mime' | |
| roiEmailParameters.roiExportParameters = new RoiExportParametersBuilder( | |
| '1', new ManagerSummary(identityId: '38'), LocalDate.now(), | |
| LocalDate.now(), 1, '2', 3).build() | |
| ManagerSummary recipient = new ManagerSummary( | |
| identityId: '38', administratorEnabled: false) | |
| organizationClient.getOrganization(1) >> | |
| new OrganizationSummary(organizationManagers: []) | |
| when: | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| [:], recipient, roiEmailParameters) | |
| then: | |
| !value | |
| 0 * notificationSender.send(_, _, _) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void shouldNotSendNotificationIfRecipientIdIsNotInOrgManagerIds() { | |
| // given | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters(); | |
| roiEmailParameters.setMimeType("mime"); | |
| ManagerSummary manager = new ManagerSummary(); | |
| manager.setIdentityId("38"); | |
| roiEmailParameters.setRoiExportParameters( | |
| new RoiExportParametersBuilder("1", manager, LocalDate.now(), | |
| LocalDate.now(), 1L, "2", 3L).build() | |
| ); | |
| ManagerSummary recipient = new ManagerSummary(); | |
| recipient.setIdentityId("38"); | |
| recipient.setAdministratorEnabled(false); | |
| OrganizationSummary orgSummary = new OrganizationSummary(); | |
| orgSummary.setOrganizationManagers(List.of()); | |
| when(organizationClient.getOrganization(1L)).thenReturn(orgSummary); | |
| // when | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| Map.of(), recipient, roiEmailParameters); | |
| // then | |
| assertThat(value).isFalse(); | |
| verify(notificationSender, never()).send( | |
| any(NotificationTemplateBundle.class), anyMap(), any(Consumer.class)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Groovy map constructor with explicit setters. Replaced Spock >> stubbing with Mockito when().thenReturn(). Replaced empty list [] with List.of(). Added explicit Long types (1L, 3L).</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 3 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 should send notification if recipient id is not in org manager ids and is admin</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should send notification if recipient id is not in org manager ids and is admin'() { | |
| given: | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters() | |
| roiEmailParameters.mimeType = 'mime' | |
| roiEmailParameters.roiExportParameters = new RoiExportParametersBuilder( | |
| '1', new ManagerSummary(identityId: '38'), LocalDate.now(), | |
| LocalDate.now(), 1, '2', 3).build() | |
| ManagerSummary recipient = new ManagerSummary(id: 38, | |
| administratorEnabled: true, timeZone: 'Europe/Paris', | |
| locale: Locale.FRANCE) | |
| organizationClient.getOrganization(1) >> | |
| new OrganizationSummary(organizationManagers: []) | |
| when: | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| [:], recipient, roiEmailParameters) | |
| then: | |
| value | |
| 1 * notificationSender.send(_, _, _) | |
| 1 * tokenService.sign(_) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void shouldSendNotificationIfRecipientIdIsNotInOrgManagerIdsAndIsAdmin() { | |
| // given | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters(); | |
| roiEmailParameters.setMimeType("mime"); | |
| ManagerSummary manager = new ManagerSummary(); | |
| manager.setIdentityId("38"); | |
| roiEmailParameters.setRoiExportParameters( | |
| new RoiExportParametersBuilder("1", manager, LocalDate.now(), | |
| LocalDate.now(), 1L, "2", 3L).build() | |
| ); | |
| ManagerSummary recipient = new ManagerSummary(); | |
| recipient.setId(38L); | |
| recipient.setAdministratorEnabled(true); | |
| recipient.setTimeZone("Europe/Paris"); | |
| recipient.setLocale(Locale.FRANCE); | |
| OrganizationSummary orgSummary = new OrganizationSummary(); | |
| orgSummary.setOrganizationManagers(List.of()); | |
| when(organizationClient.getOrganization(1L)).thenReturn(orgSummary); | |
| // when | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| Map.of(), recipient, roiEmailParameters); | |
| // then | |
| assertThat(value).isTrue(); | |
| verify(notificationSender).send( | |
| any(NotificationTemplateBundle.class), anyMap(), any(Consumer.class)); | |
| verify(tokenService).sign(any()); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Spock value assertion with assertThat().isTrue(). Replaced 1 * mock.method() with verify(mock).method(). Converted id: 38 to setId(38L) with explicit Long type.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 4 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 should send notification if recipient id is in org manager ids and is not admin</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should send notification if recipient id is in org manager ids and is not admin'() { | |
| given: | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters() | |
| roiEmailParameters.mimeType = 'mime' | |
| roiEmailParameters.roiExportParameters = new RoiExportParametersBuilder( | |
| '1', new ManagerSummary(identityId: '38'), LocalDate.now(), | |
| LocalDate.now(), 1, '2', 3).build() | |
| ManagerSummary recipient = new ManagerSummary(id: 38, | |
| administratorEnabled: true, timeZone: 'Europe/Paris', | |
| locale: Locale.FRANCE) | |
| organizationClient.getOrganization(1) >> new OrganizationSummary( | |
| organizationManagers: [new OrganizationManagerSummary(managerId: 38)]) | |
| when: | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| [:], recipient, roiEmailParameters) | |
| then: | |
| value | |
| 1 * notificationSender.send(_, _, _) | |
| 1 * tokenService.sign(_) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void shouldSendNotificationIfRecipientIdIsInOrgManagerIdsAndIsNotAdmin() { | |
| // given | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters(); | |
| roiEmailParameters.setMimeType("mime"); | |
| ManagerSummary manager = new ManagerSummary(); | |
| manager.setIdentityId("38"); | |
| roiEmailParameters.setRoiExportParameters( | |
| new RoiExportParametersBuilder("1", manager, LocalDate.now(), | |
| LocalDate.now(), 1L, "2", 3L).build() | |
| ); | |
| ManagerSummary recipient = new ManagerSummary(); | |
| recipient.setId(38L); | |
| recipient.setAdministratorEnabled(true); | |
| recipient.setTimeZone("Europe/Paris"); | |
| recipient.setLocale(Locale.FRANCE); | |
| OrganizationManagerSummary orgManager = new OrganizationManagerSummary(); | |
| orgManager.setManagerId(38L); | |
| OrganizationSummary orgSummary = new OrganizationSummary(); | |
| orgSummary.setOrganizationManagers(List.of(orgManager)); | |
| when(organizationClient.getOrganization(1L)).thenReturn(orgSummary); | |
| // when | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| Map.of(), recipient, roiEmailParameters); | |
| // then | |
| assertThat(value).isTrue(); | |
| verify(notificationSender).send( | |
| any(NotificationTemplateBundle.class), anyMap(), any(Consumer.class)); | |
| verify(tokenService).sign(any()); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Groovy list literal [new OrganizationManagerSummary(...)] with List.of(orgManager). Expanded inline object construction to explicit instantiation and setter calls.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 5 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 should send notification with file messageSource</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should send notification with file messageSource'() { | |
| given: | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters() | |
| roiEmailParameters.mimeType = 'mime' | |
| roiEmailParameters.roiExportParameters = new RoiExportParametersBuilder( | |
| '1', new ManagerSummary(identityId: '38'), LocalDate.now(), | |
| LocalDate.now(), 1, '2', 3).build() | |
| ManagerSummary recipient = new ManagerSummary(id: 38, | |
| administratorEnabled: true, timeZone: 'Europe/Paris', | |
| locale: Locale.FRANCE) | |
| organizationClient.getOrganization(1) >> new OrganizationSummary( | |
| organizationManagers: [new OrganizationManagerSummary(managerId: 38)]) | |
| Map fileData = [bucket: 'bucket', key: 'key', file: new File('test')] | |
| when: | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| fileData, recipient, roiEmailParameters) | |
| then: | |
| value | |
| 1 * notificationSender.send(_, _, _) | |
| 1 * interpolatingMessageSource.get( | |
| 'email.roi-export-completed.attachment.label', Locale.FRANCE) | |
| 1 * tokenService.sign(_) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void shouldSendNotificationWithFileMessageSource() { | |
| // given | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters(); | |
| roiEmailParameters.setMimeType("mime"); | |
| ManagerSummary manager = new ManagerSummary(); | |
| manager.setIdentityId("38"); | |
| roiEmailParameters.setRoiExportParameters( | |
| new RoiExportParametersBuilder("1", manager, LocalDate.now(), | |
| LocalDate.now(), 1L, "2", 3L).build() | |
| ); | |
| ManagerSummary recipient = new ManagerSummary(); | |
| recipient.setId(38L); | |
| recipient.setAdministratorEnabled(true); | |
| recipient.setTimeZone("Europe/Paris"); | |
| recipient.setLocale(Locale.FRANCE); | |
| OrganizationManagerSummary orgManager = new OrganizationManagerSummary(); | |
| orgManager.setManagerId(38L); | |
| OrganizationSummary orgSummary = new OrganizationSummary(); | |
| orgSummary.setOrganizationManagers(List.of(orgManager)); | |
| when(organizationClient.getOrganization(1L)).thenReturn(orgSummary); | |
| Map<String, Object> fileData = Map.of( | |
| "bucket", "bucket", "key", "key", "file", new File("test")); | |
| // when | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| fileData, recipient, roiEmailParameters); | |
| // then | |
| assertThat(value).isTrue(); | |
| verify(notificationSender).send( | |
| any(NotificationTemplateBundle.class), anyMap(), any(Consumer.class)); | |
| verify(interpolatingMessageSource).get( | |
| "email.roi-export-completed.attachment.label", Locale.FRANCE); | |
| verify(tokenService).sign(any()); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Groovy map literal [bucket: 'bucket', ...] with Java Map.of("bucket", "bucket", ...). Added generic types Map<String, Object>. Replaced Spock interaction verification with Mockito verify().</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Section: Test 6 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 should send notification with no file messageSource</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>void 'should send notification with no file messageSource'() { | |
| given: | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters() | |
| roiEmailParameters.mimeType = 'mime' | |
| roiEmailParameters.roiExportParameters = new RoiExportParametersBuilder( | |
| '1', new ManagerSummary(identityId: '38'), LocalDate.now(), | |
| LocalDate.now(), 1, '2', 3).build() | |
| ManagerSummary recipient = new ManagerSummary(id: 38, | |
| administratorEnabled: true, timeZone: 'Europe/Paris', | |
| locale: Locale.FRANCE) | |
| organizationClient.getOrganization(1) >> new OrganizationSummary( | |
| organizationManagers: [new OrganizationManagerSummary(managerId: 38)]) | |
| when: | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| null, recipient, roiEmailParameters) | |
| then: | |
| value | |
| 1 * notificationSender.send(_, _, _) | |
| 1 * interpolatingMessageSource.get( | |
| 'email.roi-export-completed.download.label', Locale.FRANCE) | |
| 1 * tokenService.sign(_) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void shouldSendNotificationWithNoFileMessageSource() { | |
| // given | |
| RoiEmailParameters roiEmailParameters = new RoiEmailParameters(); | |
| roiEmailParameters.setMimeType("mime"); | |
| ManagerSummary manager = new ManagerSummary(); | |
| manager.setIdentityId("38"); | |
| roiEmailParameters.setRoiExportParameters( | |
| new RoiExportParametersBuilder("1", manager, LocalDate.now(), | |
| LocalDate.now(), 1L, "2", 3L).build() | |
| ); | |
| ManagerSummary recipient = new ManagerSummary(); | |
| recipient.setId(38L); | |
| recipient.setAdministratorEnabled(true); | |
| recipient.setTimeZone("Europe/Paris"); | |
| recipient.setLocale(Locale.FRANCE); | |
| OrganizationManagerSummary orgManager = new OrganizationManagerSummary(); | |
| orgManager.setManagerId(38L); | |
| OrganizationSummary orgSummary = new OrganizationSummary(); | |
| orgSummary.setOrganizationManagers(List.of(orgManager)); | |
| when(organizationClient.getOrganization(1L)).thenReturn(orgSummary); | |
| // when | |
| boolean value = roiNotificationService.sendExportCompletedNotification( | |
| null, recipient, roiEmailParameters); | |
| // then | |
| assertThat(value).isTrue(); | |
| verify(notificationSender).send( | |
| any(NotificationTemplateBundle.class), anyMap(), any(Consumer.class)); | |
| verify(interpolatingMessageSource).get( | |
| "email.roi-export-completed.download.label", Locale.FRANCE); | |
| verify(tokenService).sign(any()); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Verifies download.label message key (vs attachment.label when file exists). Same pattern conversions: Spock blocks → comments, Groovy syntax → Java syntax, Spock mocking → Mockito.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| function toggleSection(header) { | |
| const content = header.nextElementSibling; | |
| const toggle = header.querySelector('.toggle'); | |
| content.classList.toggle('collapsed'); | |
| toggle.textContent = content.classList.contains('collapsed') ? '▶' : '▼'; | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment