Created
February 12, 2026 09:25
-
-
Save musketyr/421753f2ed7e6a1fc5005680c9d91210 to your computer and use it in GitHub Desktop.
Spock to JUnit 5 migration diff for GoogleAnalyticsInsightsFactorySpec (sc-185909)
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: GoogleAnalyticsInsightsFactorySpec</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: GoogleAnalyticsInsightsFactorySpec</h1> | |
| <p style="text-align: center; color: #666; margin-bottom: 20px;">Story: <a href="https://app.shortcut.com/agorapulse/story/185909">sc185909</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>import spock.lang.Specification | |
| import java.math.RoundingMode | |
| import java.time.LocalDate | |
| import java.time.LocalDateTime | |
| import java.time.ZoneOffset</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>import org.junit.jupiter.api.Test; | |
| import static org.assertj.core.api.Assertions.assertThat; | |
| import java.math.BigDecimal; | |
| import java.math.RoundingMode; | |
| import java.time.LocalDate; | |
| import java.time.LocalDateTime; | |
| import java.time.ZoneOffset; | |
| import java.util.*;</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Spock imports with JUnit 5 and AssertJ imports. Added explicit type declarations.</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 GoogleAnalyticsInsightsFactorySpec extends Specification { | |
| private static final List<LinkSummary> LINKS = mockLinks()</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>class GoogleAnalyticsInsightsFactoryTest { | |
| private static final List<LinkSummary> LINKS = mockLinks();</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Removed Specification inheritance. Renamed class with Test suffix. Added semicolons.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 1 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build whole month when data does not exist</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 build whole month when data does not exist'() { | |
| given: | |
| Ga4InsightsApiResponse statistics = new Ga4InsightsApiResponse( | |
| dimensionHeaders: [new Ga4InsightsApiResponse.Header(name: 'date'), | |
| new Ga4InsightsApiResponse.Header(name: 'sessionSource')], | |
| metricHeaders: [new Ga4InsightsApiResponse.Header(name: 'totalUsers')], | |
| rowCount: 0, | |
| rows: [] | |
| ) | |
| Map<String, String> emptyTotals = [:] | |
| when: | |
| RoiPeriodicMetric actualVisitors = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric( | |
| LocalDate.parse('2021-01-01'), LocalDate.parse('2021-01-31'), | |
| statistics, emptyTotals, emptyTotals, MetricType.VISITOR.ga4Code) | |
| then: | |
| actualVisitors.countByDay.size() == 31 | |
| actualVisitors.countByDay*.value.sum() == 0 | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_whole_month_when_data_does_not_exist() { | |
| // given | |
| Ga4InsightsApiResponse statistics = Ga4InsightsApiResponse.builder() | |
| .dimensionHeaders(List.of( | |
| Ga4InsightsApiResponse.Header.builder().name("date").build(), | |
| Ga4InsightsApiResponse.Header.builder().name("sessionSource").build())) | |
| .metricHeaders(List.of( | |
| Ga4InsightsApiResponse.Header.builder().name("totalUsers").build())) | |
| .rowCount(0) | |
| .rows(List.of()) | |
| .build(); | |
| Map<String, String> emptyTotals = Map.of(); | |
| // when | |
| RoiPeriodicMetric actualVisitors = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric( | |
| LocalDate.parse("2021-01-01"), | |
| LocalDate.parse("2021-01-31"), | |
| statistics, | |
| emptyTotals, | |
| emptyTotals, | |
| MetricType.VISITOR.getGa4Code()); | |
| // then | |
| assertThat(actualVisitors.getCountByDay()).hasSize(31); | |
| assertThat(actualVisitors.getCountByDay().values().stream() | |
| .reduce(BigDecimal.ZERO, BigDecimal::add)) | |
| .isEqualByComparingTo(BigDecimal.ZERO); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Added @Test annotation. Converted Groovy map syntax to builder pattern. Replaced == with AssertJ assertThat(). Used getters instead of property access.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 2 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build visitors view when visitors data exist</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 build visitors view when visitors data exist'() { | |
| given: | |
| Ga4InsightsApiResponse statistics = new Ga4InsightsApiResponse( | |
| dimensionHeaders: [...], | |
| metricHeaders: [...], | |
| rowCount: 3, | |
| rows: [...] | |
| ) | |
| Map<String, String> totals = ['totalUsers': '40'] | |
| Map<String, String> previousTotals = ['totalUsers': '80'] | |
| when: | |
| RoiPeriodicMetric actualVisitors = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...) | |
| then: | |
| actualVisitors == RoiPeriodicMetric.builder() | |
| .count(BigDecimal.valueOf(40)) | |
| .countByDay(new TreeMap<String, BigDecimal>(['2021-01-01': 10.0, '2021-01-02': 30.0])) | |
| ... | |
| .build() | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_visitors_view_when_visitors_data_exist() { | |
| // given | |
| Ga4InsightsApiResponse statistics = Ga4InsightsApiResponse.builder() | |
| .dimensionHeaders(List.of(...)) | |
| .metricHeaders(List.of(...)) | |
| .rowCount(3) | |
| .rows(List.of(...)) | |
| .build(); | |
| Map<String, String> totals = Map.of("totalUsers", "40"); | |
| Map<String, String> previousTotals = Map.of("totalUsers", "80"); | |
| // when | |
| RoiPeriodicMetric actualVisitors = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...); | |
| // then | |
| RoiPeriodicMetric expected = RoiPeriodicMetric.builder() | |
| .count(BigDecimal.valueOf(40)) | |
| .countByDay(new TreeMap<>(Map.of("2021-01-01", BigDecimal.valueOf(10.0), ...))) | |
| ... | |
| .build(); | |
| assertThat(actualVisitors).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced Groovy map literals with Map.of(). Used builder pattern for object construction. Replaced Spock == with assertThat().isEqualTo().</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 3 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build goal completion view when goal completion data exist</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 build goal completion view when goal completion data exist'() { | |
| given: | |
| Ga4InsightsApiResponse statistics = new Ga4InsightsApiResponse(...) | |
| Map<String, String> totals = ['totalUsers': '14', 'eventCount': '40'] | |
| Map<String, String> previousTotals = ['totalUsers': '14', 'eventCount': '80'] | |
| when: | |
| RoiPeriodicMetric actualGoalCompletion = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...) | |
| then: | |
| actualGoalCompletion == RoiPeriodicMetric.builder()... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_goal_completion_view_when_goal_completion_data_exist() { | |
| // given | |
| Ga4InsightsApiResponse statistics = Ga4InsightsApiResponse.builder()...build(); | |
| Map<String, String> totals = Map.of("totalUsers", "14", "eventCount", "40"); | |
| Map<String, String> previousTotals = Map.of("totalUsers", "14", "eventCount", "80"); | |
| // when | |
| RoiPeriodicMetric actualGoalCompletion = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...); | |
| // then | |
| RoiPeriodicMetric expected = RoiPeriodicMetric.builder()...build(); | |
| assertThat(actualGoalCompletion).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Same pattern - @Test annotation, builder pattern, Map.of(), assertThat().isEqualTo().</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 4 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build conversion view when conversion data exist</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 build conversion view when conversion data exist'() { | |
| given: | |
| ... | |
| when: | |
| RoiPeriodicMetric actualConversion = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...) | |
| then: | |
| actualConversion == RoiPeriodicMetric.builder()... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_conversion_view_when_conversion_data_exist() { | |
| // given | |
| ... | |
| // when | |
| RoiPeriodicMetric actualConversion = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...); | |
| // then | |
| assertThat(actualConversion).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Standard migration pattern applied.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 5 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build goal value view when goal value data exist</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 build goal value view when goal value data exist'() { | |
| ... | |
| then: | |
| actualGoalValue == RoiPeriodicMetric.builder() | |
| .variationPercent(new BigDecimal(-60)) | |
| .build() | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_goal_value_view_when_goal_value_data_exist() { | |
| ... | |
| // then | |
| assertThat(actualGoalValue).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Standard migration pattern applied.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 6 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build generated revenue view when generated revenue data exist</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 build generated revenue view when generated revenue data exist'() { | |
| ... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_generated_revenue_view_when_generated_revenue_data_exist() { | |
| ... | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Standard migration pattern applied.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 7 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build funnel by source with sampled data</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 build funnel by source with sampled data'() { | |
| given: | |
| Ga4InsightsApiResponse statistics = new Ga4InsightsApiResponse( | |
| dimensionHeaders: [new Ga4InsightsApiResponse.Header(name: 'sessionSource')], | |
| metricHeaders: [...], | |
| totals: [new Ga4InsightsApiResponse.Row(metricValues: [...])], | |
| rowCount: 6, | |
| rows: [...] | |
| ) | |
| when: | |
| RoiKeyPerformance actualFunnelBySource = GoogleAnalyticsInsightsFactory.makeFunnelBySource(statistics) | |
| then: | |
| RoiKeyPerformance expectedFunnelBySource = new RoiKeyPerformance( | |
| performanceMetrics: [...], | |
| samplingPercent: 100.0 | |
| ) | |
| actualFunnelBySource == expectedFunnelBySource | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_funnel_by_source_with_sampled_data() { | |
| // given | |
| Ga4InsightsApiResponse statistics = Ga4InsightsApiResponse.builder() | |
| .dimensionHeaders(List.of(Ga4InsightsApiResponse.Header.builder().name("sessionSource").build())) | |
| .metricHeaders(List.of(...)) | |
| .totals(List.of(Ga4InsightsApiResponse.Row.builder().metricValues(...).build())) | |
| .rowCount(6) | |
| .rows(List.of(...)) | |
| .build(); | |
| // when | |
| RoiKeyPerformance actualFunnelBySource = GoogleAnalyticsInsightsFactory.makeFunnelBySource(statistics); | |
| // then | |
| RoiKeyPerformance expectedFunnelBySource = new RoiKeyPerformance( | |
| List.of(...), | |
| BigDecimal.valueOf(100.0)); | |
| assertThat(actualFunnelBySource).isEqualTo(expectedFunnelBySource); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Complex test with many nested objects. Converted all Groovy map literals to builder pattern and Java collections.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 8 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build funnel by source without sampled data</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 build funnel by source without sampled data'() { | |
| ... | |
| then: | |
| funnelBySource.samplingPercent == 100 | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_funnel_by_source_without_sampled_data() { | |
| ... | |
| // then | |
| assertThat(funnelBySource.getSamplingPercent()).isEqualByComparingTo(BigDecimal.valueOf(100)); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Used getter method and isEqualByComparingTo for BigDecimal comparison.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 9 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should make performance</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 make performance'() { | |
| given: | |
| Ga4InsightsApiResponse contentStatistics = ... | |
| LinkSummary linkSummary = new LinkSummary(uid: 'linkUid1') | |
| when: | |
| RoiKeyPerformanceMetrics performance = GoogleAnalyticsInsightsFactory.makePerformance(contentStatistics, linkSummary) | |
| then: | |
| performance == RoiKeyPerformanceMetrics.builder()... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_make_performance() { | |
| // given | |
| Ga4InsightsApiResponse contentStatistics = ...; | |
| LinkSummary linkSummary = LinkSummary.builder().uid("linkUid1").build(); | |
| // when | |
| RoiKeyPerformanceMetrics performance = GoogleAnalyticsInsightsFactory.makePerformance(contentStatistics, linkSummary); | |
| // then | |
| assertThat(performance).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Converted Groovy constructor syntax to builder pattern.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 10 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should build roi content metrics</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 build roi content metrics'() { | |
| given: | |
| AccountSummary account = new AccountSummary(alias: 'test', uid: 'facebook_1', service: Service.facebook) | |
| LinkSummary link = new LinkSummary(...) | |
| PostInsightSummary insight = new PostInsightSummary( | |
| attachment: new PostInsightAttachment(multiAttachmentEnabled: true, type: 'picture', url: 'url'), | |
| ... | |
| ) | |
| RoiKeyPerformanceMetrics metrics = ... | |
| when: | |
| RoiContentMetrics actualRoiContentMetrics = GoogleAnalyticsInsightsFactory.buildRoiContentMetrics(account, link, insight, metrics) | |
| then: | |
| actualRoiContentMetrics == RoiContentMetrics.builder()... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_roi_content_metrics() { | |
| // given | |
| AccountSummary account = AccountSummary.builder() | |
| .alias("test") | |
| .uid("facebook_1") | |
| .service(Service.facebook) | |
| .build(); | |
| LinkSummary link = LinkSummary.builder()...build(); | |
| PostInsightSummary insight = PostInsightSummary.builder() | |
| .attachment(PostInsightAttachment.builder() | |
| .multiAttachmentEnabled(true) | |
| .type("picture") | |
| .url("url") | |
| .build()) | |
| ... | |
| .build(); | |
| RoiKeyPerformanceMetrics metrics = ...; | |
| // when | |
| RoiContentMetrics actualRoiContentMetrics = GoogleAnalyticsInsightsFactory.buildRoiContentMetrics(...); | |
| // then | |
| assertThat(actualRoiContentMetrics).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> All nested objects converted to builder pattern. Single quotes to double quotes.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 11 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should get link uids</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 get link uids'() { | |
| ... | |
| then: | |
| uids == new HashSet(['ap_ONE', 'ap_THREE', 'ap_FOUR', 'ap_FIVE']) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_get_link_uids() { | |
| ... | |
| // then | |
| assertThat(uids).containsExactlyInAnyOrder("ap_ONE", "ap_THREE", "ap_FOUR", "ap_FIVE"); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Replaced HashSet comparison with AssertJ containsExactlyInAnyOrder for better readability.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 12 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should merge row into funnel by profile metrics - add to existing line</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 merge row into funnel by profile metrics - add to existing line'() { | |
| given: | |
| RoiKeyPerformanceMetrics metric = ... | |
| List<RoiKeyPerformanceMetrics> currentMetrics = [...] | |
| when: | |
| GoogleAnalyticsInsightsFactory.aggregateMetricByProfile(currentMetrics, 'facebook_1', metric) | |
| then: | |
| currentMetrics == [...] | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_merge_row_into_funnel_by_profile_metrics_add_to_existing_line() { | |
| // given | |
| RoiKeyPerformanceMetrics metric = ...; | |
| List<RoiKeyPerformanceMetrics> currentMetrics = new ArrayList<>(); | |
| currentMetrics.add(...); | |
| // when | |
| GoogleAnalyticsInsightsFactory.aggregateMetricByProfile(currentMetrics, "facebook_1", metric); | |
| // then | |
| assertThat(currentMetrics).containsExactly(...); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Groovy list literals to ArrayList. Used containsExactly for list comparison.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 13 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should merge row into funnel by profile metrics - create new line</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 merge row into funnel by profile metrics - create new line'() { | |
| ... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_merge_row_into_funnel_by_profile_metrics_create_new_line() { | |
| ... | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Standard migration pattern applied.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 14 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should merge row into funnel by team member metrics - add to existing line</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 merge row into funnel by team member metrics - add to existing line'() { | |
| ... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_merge_row_into_funnel_by_team_member_metrics_add_to_existing_line() { | |
| ... | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Standard migration pattern applied.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 15 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should merge row into funnel by team member metrics - create new line</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 merge row into funnel by team member metrics - create new line'() { | |
| ... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_merge_row_into_funnel_by_team_member_metrics_create_new_line() { | |
| ... | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Standard migration pattern applied.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 16 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should sumDataForContent</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 sumDataForContent'() { | |
| given: | |
| List<Ga4InsightsApiResponse> contentStatistics = [...] | |
| when: | |
| ContentPerformance performance = GoogleAnalyticsInsightsFactory.sumDataForContent(contentStatistics) | |
| then: | |
| performance == ContentPerformance.builder() | |
| .tracked(true) | |
| .visitorCount(32) | |
| ... | |
| .build() | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_sum_data_for_content() { | |
| // given | |
| List<Ga4InsightsApiResponse> contentStatistics = List.of(...); | |
| // when | |
| ContentPerformance performance = GoogleAnalyticsInsightsFactory.sumDataForContent(contentStatistics); | |
| // then | |
| ContentPerformance expected = ContentPerformance.builder() | |
| .tracked(true) | |
| .visitorCount(32) | |
| ... | |
| .build(); | |
| assertThat(performance).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Standard migration pattern applied.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 17 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 build metric - empty</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 'build metric - empty'() { | |
| given: | |
| Map<String, String> totalsByMetric = [:] | |
| Map<String, String> valuesByMetric = [:] | |
| when: | |
| RoiKeyPerformanceMetrics metric = GoogleAnalyticsInsightsFactory.buildMetric(totalsByMetric, valuesByMetric) | |
| then: | |
| metric == RoiKeyPerformanceMetrics.builder()... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_metric_empty() { | |
| // given | |
| Map<String, String> totalsByMetric = Map.of(); | |
| Map<String, String> valuesByMetric = Map.of(); | |
| // when | |
| RoiKeyPerformanceMetrics metric = GoogleAnalyticsInsightsFactory.buildMetric(totalsByMetric, valuesByMetric); | |
| // then | |
| assertThat(metric).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Groovy [:] to Map.of(). Renamed test method with "should_" prefix.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Test 18 --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 build metric - with data</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 'build metric - with data'() { | |
| given: | |
| Map<String, String> totalsByMetric = ['totalUsers': '1', 'eventValue': '20.0', ...] | |
| Map<String, String> valuesByMetric = ['totalUsers': '1', 'eventValue': '2.0', ...] | |
| when: | |
| RoiKeyPerformanceMetrics metric = GoogleAnalyticsInsightsFactory.buildMetric(totalsByMetric, valuesByMetric) | |
| then: | |
| metric == RoiKeyPerformanceMetrics.builder()... | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>@Test | |
| void should_build_metric_with_data() { | |
| // given | |
| Map<String, String> totalsByMetric = Map.of( | |
| "totalUsers", "1", | |
| "eventValue", "20.0", | |
| ...); | |
| Map<String, String> valuesByMetric = Map.of( | |
| "totalUsers", "1", | |
| "eventValue", "2.0", | |
| ...); | |
| // when | |
| RoiKeyPerformanceMetrics metric = GoogleAnalyticsInsightsFactory.buildMetric(totalsByMetric, valuesByMetric); | |
| // then | |
| assertThat(metric).isEqualTo(expected); | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Groovy map literals to Map.of(). Renamed test method with "should_" prefix.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Helper Method --> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🔧 mockLinks() helper method</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>private static List<LinkSummary> mockLinks() { | |
| List<LinkSummary> linkMocks = [] | |
| linkMocks << new LinkSummary( | |
| uid: 'ap_ONE', | |
| accountUid: 'facebook_1', | |
| createdByFeature: 'PUBLISHING', | |
| ... | |
| ) | |
| ... | |
| return linkMocks | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>private static List<LinkSummary> mockLinks() { | |
| List<LinkSummary> linkMocks = new ArrayList<>(); | |
| linkMocks.add(LinkSummary.builder() | |
| .uid("ap_ONE") | |
| .accountUid("facebook_1") | |
| .createdByFeature("PUBLISHING") | |
| ... | |
| .build()); | |
| ... | |
| return linkMocks; | |
| }</pre> | |
| </div> | |
| </div> | |
| <div class="summary"> | |
| <p><strong>Changes:</strong> Groovy << operator to .add(). Map-style construction to builder pattern. Single to double quotes.</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