Skip to content

Instantly share code, notes, and snippets.

@musketyr
Created February 12, 2026 09:25
Show Gist options
  • Select an option

  • Save musketyr/421753f2ed7e6a1fc5005680c9d91210 to your computer and use it in GitHub Desktop.

Select an option

Save musketyr/421753f2ed7e6a1fc5005680c9d91210 to your computer and use it in GitHub Desktop.
Spock to JUnit 5 migration diff for GoogleAnalyticsInsightsFactorySpec (sc-185909)
<!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&lt;LinkSummary&gt; LINKS = mockLinks()</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>class GoogleAnalyticsInsightsFactoryTest {
private static final List&lt;LinkSummary&gt; 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&lt;String, String&gt; 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&lt;String, String&gt; 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&lt;String, String&gt; totals = ['totalUsers': '40']
Map&lt;String, String&gt; previousTotals = ['totalUsers': '80']
when:
RoiPeriodicMetric actualVisitors = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...)
then:
actualVisitors == RoiPeriodicMetric.builder()
.count(BigDecimal.valueOf(40))
.countByDay(new TreeMap&lt;String, BigDecimal&gt;(['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&lt;String, String&gt; totals = Map.of("totalUsers", "40");
Map&lt;String, String&gt; previousTotals = Map.of("totalUsers", "80");
// when
RoiPeriodicMetric actualVisitors = GoogleAnalyticsInsightsFactory.makePeriodicDataByMetric(...);
// then
RoiPeriodicMetric expected = RoiPeriodicMetric.builder()
.count(BigDecimal.valueOf(40))
.countByDay(new TreeMap&lt;&gt;(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&lt;String, String&gt; totals = ['totalUsers': '14', 'eventCount': '40']
Map&lt;String, String&gt; 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&lt;String, String&gt; totals = Map.of("totalUsers", "14", "eventCount", "40");
Map&lt;String, String&gt; 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&lt;RoiKeyPerformanceMetrics&gt; 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&lt;RoiKeyPerformanceMetrics&gt; currentMetrics = new ArrayList&lt;&gt;();
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&lt;Ga4InsightsApiResponse&gt; 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&lt;Ga4InsightsApiResponse&gt; 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&lt;String, String&gt; totalsByMetric = [:]
Map&lt;String, String&gt; 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&lt;String, String&gt; totalsByMetric = Map.of();
Map&lt;String, String&gt; 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&lt;String, String&gt; totalsByMetric = ['totalUsers': '1', 'eventValue': '20.0', ...]
Map&lt;String, String&gt; 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&lt;String, String&gt; totalsByMetric = Map.of(
"totalUsers", "1",
"eventValue", "20.0",
...);
Map&lt;String, String&gt; 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&lt;LinkSummary&gt; mockLinks() {
List&lt;LinkSummary&gt; linkMocks = []
linkMocks &lt;&lt; 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&lt;LinkSummary&gt; mockLinks() {
List&lt;LinkSummary&gt; linkMocks = new ArrayList&lt;&gt;();
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 &lt;&lt; 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