From b7a8627bcfa64d2611e08f4d7963f35956e07400 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 28 May 2025 12:50:54 +0200
Subject: [PATCH 1/3] test: dice service
---
.../casino/blackjack/BlackJackGameEntity.java | 2 -
.../java/de/szut/casino/dice/DiceDto.java | 2 +
.../java/de/szut/casino/dice/DiceService.java | 5 +-
.../de/szut/casino/dice/DiceServiceTest.java | 216 ++++++++++++++++++
4 files changed, 221 insertions(+), 4 deletions(-)
create mode 100644 backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameEntity.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameEntity.java
index c9f57d7..4f22c9d 100644
--- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameEntity.java
+++ b/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameEntity.java
@@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import de.szut.casino.user.UserEntity;
import jakarta.persistence.*;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
diff --git a/backend/src/main/java/de/szut/casino/dice/DiceDto.java b/backend/src/main/java/de/szut/casino/dice/DiceDto.java
index ecbf3d7..f0caf48 100644
--- a/backend/src/main/java/de/szut/casino/dice/DiceDto.java
+++ b/backend/src/main/java/de/szut/casino/dice/DiceDto.java
@@ -5,12 +5,14 @@ import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
+import lombok.NoArgsConstructor;
import lombok.Setter;
import java.math.BigDecimal;
@Getter
@Setter
+@NoArgsConstructor
public class DiceDto extends BetDto {
private boolean rollOver;
diff --git a/backend/src/main/java/de/szut/casino/dice/DiceService.java b/backend/src/main/java/de/szut/casino/dice/DiceService.java
index 71e4584..836620b 100644
--- a/backend/src/main/java/de/szut/casino/dice/DiceService.java
+++ b/backend/src/main/java/de/szut/casino/dice/DiceService.java
@@ -11,10 +11,11 @@ import java.util.Random;
@Service
public class DiceService {
private static final int MAX_DICE_VALUE = 100;
- private final Random random = new Random();
+ private final Random random;
private final BalanceService balanceService;
- public DiceService(BalanceService balanceService) {
+ public DiceService(Random random, BalanceService balanceService) {
+ this.random = random;
this.balanceService = balanceService;
}
diff --git a/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java b/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
new file mode 100644
index 0000000..21ca6cf
--- /dev/null
+++ b/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
@@ -0,0 +1,216 @@
+package de.szut.casino.dice;
+
+import de.szut.casino.shared.service.BalanceService;
+import de.szut.casino.user.UserEntity;
+import org.junit.jupiter.api.BeforeEach;
+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 java.math.BigDecimal;
+import java.util.Random;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class DiceServiceTest {
+
+ @Mock
+ private BalanceService balanceService;
+
+ @Mock
+ private Random random;
+
+ @InjectMocks
+ private DiceService diceService;
+
+ private UserEntity user;
+ private DiceDto diceDto;
+
+ @BeforeEach
+ void setUp() {
+ user = new UserEntity();
+ user.setId(1L);
+ user.setBalance(BigDecimal.valueOf(1000));
+
+ diceDto = new DiceDto();
+ diceDto.setBetAmount(BigDecimal.valueOf(10));
+ diceDto.setTargetValue(BigDecimal.valueOf(50));
+ diceDto.setRollOver(true);
+ }
+
+ @Test
+ void play_rollOver_win() {
+ diceDto.setRollOver(true);
+ diceDto.setTargetValue(BigDecimal.valueOf(50));
+ when(random.nextInt(anyInt())).thenReturn(55);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(56), result.getRolledValue());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
+ }
+
+ @Test
+ void play_rollOver_lose() {
+ diceDto.setRollOver(true);
+ diceDto.setTargetValue(BigDecimal.valueOf(50));
+ when(random.nextInt(anyInt())).thenReturn(49);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertFalse(result.isWin());
+ assertEquals(BigDecimal.valueOf(50), result.getRolledValue());
+ assertEquals(BigDecimal.ZERO, result.getPayout());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
+ }
+
+ @Test
+ void play_rollUnder_win() {
+ diceDto.setRollOver(false);
+ diceDto.setTargetValue(BigDecimal.valueOf(50));
+ when(random.nextInt(anyInt())).thenReturn(48);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(49), result.getRolledValue());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
+ }
+
+ @Test
+ void play_rollUnder_lose() {
+ diceDto.setRollOver(false);
+ diceDto.setTargetValue(BigDecimal.valueOf(50));
+ when(random.nextInt(anyInt())).thenReturn(50);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertFalse(result.isWin());
+ assertEquals(BigDecimal.valueOf(51), result.getRolledValue());
+ assertEquals(BigDecimal.ZERO, result.getPayout());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
+ }
+
+ @Test
+ void play_rollOver_targetValueOne_lose() {
+ diceDto.setRollOver(true);
+ diceDto.setTargetValue(BigDecimal.valueOf(1));
+ when(random.nextInt(anyInt())).thenReturn(0);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertFalse(result.isWin());
+ assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
+ assertEquals(BigDecimal.ZERO, result.getPayout());
+ }
+
+ @Test
+ void play_rollUnder_targetValueOne_win() {
+ diceDto.setRollOver(false);
+ diceDto.setTargetValue(BigDecimal.valueOf(1));
+ when(random.nextInt(anyInt())).thenReturn(0);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertFalse(result.isWin());
+ assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
+ assertEquals(BigDecimal.ZERO, result.getPayout());
+ }
+
+ @Test
+ void play_rollOver_targetValueNinetyNine_win() {
+ diceDto.setRollOver(true);
+ diceDto.setTargetValue(BigDecimal.valueOf(99));
+ when(random.nextInt(anyInt())).thenReturn(99);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
+ }
+
+ @Test
+ void play_rollUnder_targetValueNinetyNine_win() {
+ diceDto.setRollOver(false);
+ diceDto.setTargetValue(BigDecimal.valueOf(99));
+ when(random.nextInt(anyInt())).thenReturn(97);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(98), result.getRolledValue());
+ }
+
+ @Test
+ void play_rollOver_targetValueOneHundred_lose() {
+ diceDto.setRollOver(true);
+ diceDto.setTargetValue(BigDecimal.valueOf(100));
+ when(random.nextInt(anyInt())).thenReturn(99);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertFalse(result.isWin());
+ assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
+ assertEquals(BigDecimal.ZERO, result.getPayout());
+ }
+
+ @Test
+ void play_rollUnder_targetValueOneHundred_win() {
+ diceDto.setRollOver(false);
+ diceDto.setTargetValue(BigDecimal.valueOf(100));
+ when(random.nextInt(anyInt())).thenReturn(98);
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(99), result.getRolledValue());
+ }
+
+ @Test
+ void play_payoutCalculationCorrect() {
+ diceDto.setRollOver(true);
+ diceDto.setTargetValue(BigDecimal.valueOf(75));
+ when(random.nextInt(anyInt())).thenReturn(75);
+
+ // Multiplier for win chance 25: (100-1)/25 = 99/25 = 3.96
+ // Payout: 10 * 3.96 = 39.6
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(39.6).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
+ }
+
+ @Test
+ void play_payoutCalculationCorrect_rollUnder() {
+ diceDto.setRollOver(false);
+ diceDto.setTargetValue(BigDecimal.valueOf(25));
+ when(random.nextInt(anyInt())).thenReturn(0);
+
+ // Multiplier for win chance 24: (100-1)/24 = 99/24 = 4.125
+ // Payout: 10 * 4.125 = 41.25
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(41.25).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
+ }
+
+ @Test
+ void play_betAmountSubtracted() {
+ when(random.nextInt(anyInt())).thenReturn(50);
+
+ diceService.play(user, diceDto);
+
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ }
+}
From 78b8f4696c658d15c4b388577dce59fc5a85d7be Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 28 May 2025 12:58:40 +0200
Subject: [PATCH 2/3] test: refactor
---
.../de/szut/casino/dice/DiceServiceTest.java | 61 +++++++++++++++----
1 file changed, 48 insertions(+), 13 deletions(-)
diff --git a/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java b/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
index 21ca6cf..ec5f979 100644
--- a/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
+++ b/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
@@ -10,6 +10,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.util.Random;
import static org.junit.jupiter.api.Assertions.*;
@@ -101,78 +102,112 @@ class DiceServiceTest {
}
@Test
- void play_rollOver_targetValueOne_lose() {
+ void play_rollOver_targetValueOne_rolledOne_lose() {
diceDto.setRollOver(true);
diceDto.setTargetValue(BigDecimal.valueOf(1));
- when(random.nextInt(anyInt())).thenReturn(0);
+ when(random.nextInt(anyInt())).thenReturn(0); // rolledValue = 1
DiceResult result = diceService.play(user, diceDto);
assertFalse(result.isWin());
assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
assertEquals(BigDecimal.ZERO, result.getPayout());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
}
@Test
- void play_rollUnder_targetValueOne_win() {
+ void play_rollOver_targetValueOne_rolledTwo_win() {
+ diceDto.setRollOver(true);
+ diceDto.setTargetValue(BigDecimal.valueOf(1));
+ when(random.nextInt(anyInt())).thenReturn(1); // rolledValue = 2
+
+ DiceResult result = diceService.play(user, diceDto);
+
+ assertTrue(result.isWin());
+ assertEquals(BigDecimal.valueOf(2), result.getRolledValue());
+ // Win chance for target 1 (roll over) is 99. Multiplier = (100-1)/99 = 1
+ assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
+ }
+
+ @Test
+ void play_rollUnder_targetValueOne_alwaysLose_winChanceZero() {
diceDto.setRollOver(false);
diceDto.setTargetValue(BigDecimal.valueOf(1));
- when(random.nextInt(anyInt())).thenReturn(0);
+ when(random.nextInt(anyInt())).thenReturn(0); // rolledValue = 1
DiceResult result = diceService.play(user, diceDto);
assertFalse(result.isWin());
assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
assertEquals(BigDecimal.ZERO, result.getPayout());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
}
@Test
- void play_rollOver_targetValueNinetyNine_win() {
+ void play_rollOver_targetValueNinetyNine_rolledHundred_win() {
diceDto.setRollOver(true);
diceDto.setTargetValue(BigDecimal.valueOf(99));
- when(random.nextInt(anyInt())).thenReturn(99);
+ when(random.nextInt(anyInt())).thenReturn(99); // rolledValue = 100
DiceResult result = diceService.play(user, diceDto);
assertTrue(result.isWin());
assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
+ // Win chance for target 99 (roll over) is 1. Multiplier = (100-1)/1 = 99
+ assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99)).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
}
@Test
- void play_rollUnder_targetValueNinetyNine_win() {
+ void play_rollUnder_targetValueNinetyNine_rolledNinetyEight_win() {
diceDto.setRollOver(false);
diceDto.setTargetValue(BigDecimal.valueOf(99));
- when(random.nextInt(anyInt())).thenReturn(97);
+ when(random.nextInt(anyInt())).thenReturn(97); // rolledValue = 98
DiceResult result = diceService.play(user, diceDto);
assertTrue(result.isWin());
assertEquals(BigDecimal.valueOf(98), result.getRolledValue());
+ // Win chance for target 99 (roll under) is 98. Multiplier = (100-1)/98 = 99/98
+ assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99).divide(BigDecimal.valueOf(98), 4, RoundingMode.HALF_UP)), result.getPayout());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
}
@Test
- void play_rollOver_targetValueOneHundred_lose() {
+ void play_rollOver_targetValueOneHundred_alwaysLose_winChanceZero() {
diceDto.setRollOver(true);
diceDto.setTargetValue(BigDecimal.valueOf(100));
- when(random.nextInt(anyInt())).thenReturn(99);
+ when(random.nextInt(anyInt())).thenReturn(99); // rolledValue = 100
DiceResult result = diceService.play(user, diceDto);
assertFalse(result.isWin());
assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
assertEquals(BigDecimal.ZERO, result.getPayout());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
}
@Test
- void play_rollUnder_targetValueOneHundred_win() {
- diceDto.setRollOver(false);
+ void play_rollUnder_targetValueOneHundred_rolledNinetyNine_win() {
+ diceDto.setRollOver(false); // Assuming a typo in original, should be setRollOver(false)
diceDto.setTargetValue(BigDecimal.valueOf(100));
- when(random.nextInt(anyInt())).thenReturn(98);
+ when(random.nextInt(anyInt())).thenReturn(98); // rolledValue = 99
DiceResult result = diceService.play(user, diceDto);
assertTrue(result.isWin());
assertEquals(BigDecimal.valueOf(99), result.getRolledValue());
+ // Win chance for target 100 (roll under) is 99. Multiplier = (100-1)/99 = 1
+ assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros());
+ verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
+ verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
}
@Test
From 3e1c15e023aac8d8c97176bb5cb6618e5f3e4233 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 28 May 2025 13:01:18 +0200
Subject: [PATCH 3/3] test: adjust commments
---
.../de/szut/casino/dice/DiceServiceTest.java | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java b/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
index ec5f979..6b2e230 100644
--- a/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
+++ b/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
@@ -105,7 +105,7 @@ class DiceServiceTest {
void play_rollOver_targetValueOne_rolledOne_lose() {
diceDto.setRollOver(true);
diceDto.setTargetValue(BigDecimal.valueOf(1));
- when(random.nextInt(anyInt())).thenReturn(0); // rolledValue = 1
+ when(random.nextInt(anyInt())).thenReturn(0);
DiceResult result = diceService.play(user, diceDto);
@@ -120,7 +120,7 @@ class DiceServiceTest {
void play_rollOver_targetValueOne_rolledTwo_win() {
diceDto.setRollOver(true);
diceDto.setTargetValue(BigDecimal.valueOf(1));
- when(random.nextInt(anyInt())).thenReturn(1); // rolledValue = 2
+ when(random.nextInt(anyInt())).thenReturn(1);
DiceResult result = diceService.play(user, diceDto);
@@ -136,7 +136,7 @@ class DiceServiceTest {
void play_rollUnder_targetValueOne_alwaysLose_winChanceZero() {
diceDto.setRollOver(false);
diceDto.setTargetValue(BigDecimal.valueOf(1));
- when(random.nextInt(anyInt())).thenReturn(0); // rolledValue = 1
+ when(random.nextInt(anyInt())).thenReturn(0);
DiceResult result = diceService.play(user, diceDto);
@@ -151,7 +151,7 @@ class DiceServiceTest {
void play_rollOver_targetValueNinetyNine_rolledHundred_win() {
diceDto.setRollOver(true);
diceDto.setTargetValue(BigDecimal.valueOf(99));
- when(random.nextInt(anyInt())).thenReturn(99); // rolledValue = 100
+ when(random.nextInt(anyInt())).thenReturn(99);
DiceResult result = diceService.play(user, diceDto);
@@ -167,7 +167,7 @@ class DiceServiceTest {
void play_rollUnder_targetValueNinetyNine_rolledNinetyEight_win() {
diceDto.setRollOver(false);
diceDto.setTargetValue(BigDecimal.valueOf(99));
- when(random.nextInt(anyInt())).thenReturn(97); // rolledValue = 98
+ when(random.nextInt(anyInt())).thenReturn(97);
DiceResult result = diceService.play(user, diceDto);
@@ -183,7 +183,7 @@ class DiceServiceTest {
void play_rollOver_targetValueOneHundred_alwaysLose_winChanceZero() {
diceDto.setRollOver(true);
diceDto.setTargetValue(BigDecimal.valueOf(100));
- when(random.nextInt(anyInt())).thenReturn(99); // rolledValue = 100
+ when(random.nextInt(anyInt())).thenReturn(99);
DiceResult result = diceService.play(user, diceDto);
@@ -196,9 +196,9 @@ class DiceServiceTest {
@Test
void play_rollUnder_targetValueOneHundred_rolledNinetyNine_win() {
- diceDto.setRollOver(false); // Assuming a typo in original, should be setRollOver(false)
+ diceDto.setRollOver(false);
diceDto.setTargetValue(BigDecimal.valueOf(100));
- when(random.nextInt(anyInt())).thenReturn(98); // rolledValue = 99
+ when(random.nextInt(anyInt())).thenReturn(98);
DiceResult result = diceService.play(user, diceDto);