diff --git a/pom.xml b/pom.xml
index 543c1aa50..c01098191 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
org.junit.jupiter
junit-jupiter
- 5.11.4
+ 6.0.1
test
@@ -28,9 +28,14 @@
org.mockito
mockito-junit-jupiter
- 5.15.2
+ 5.21.0
test
+
+ org.awaitility
+ awaitility
+ 4.3.0
+
@@ -57,6 +62,19 @@
+
+ org.pitest
+ pitest-maven
+ 1.22.0
+
+
+ org.pitest
+ pitest-junit5-plugin
+ 1.2.2
+
+
+
+
org.jacoco
jacoco-maven-plugin
diff --git a/src/main/java/com/example/payment/DatabaseConnection.java b/src/main/java/com/example/payment/DatabaseConnection.java
new file mode 100644
index 000000000..22b856e38
--- /dev/null
+++ b/src/main/java/com/example/payment/DatabaseConnection.java
@@ -0,0 +1,5 @@
+package com.example.payment;
+
+public interface DatabaseConnection {
+ void executeUpdate(String query);
+}
diff --git a/src/main/java/com/example/payment/EmailService.java b/src/main/java/com/example/payment/EmailService.java
new file mode 100644
index 000000000..e748c2fa2
--- /dev/null
+++ b/src/main/java/com/example/payment/EmailService.java
@@ -0,0 +1,5 @@
+package com.example.payment;
+
+public interface EmailService {
+ void sendPaymentConfirmation(String email, double amount);
+}
diff --git a/src/main/java/com/example/payment/PaymentApi.java b/src/main/java/com/example/payment/PaymentApi.java
new file mode 100644
index 000000000..5f741d58c
--- /dev/null
+++ b/src/main/java/com/example/payment/PaymentApi.java
@@ -0,0 +1,5 @@
+package com.example.payment;
+
+public interface PaymentApi {
+ PaymentApiResponse charge(String apiKey, double amount);
+}
diff --git a/src/main/java/com/example/payment/PaymentApiResponse.java b/src/main/java/com/example/payment/PaymentApiResponse.java
new file mode 100644
index 000000000..208d2b111
--- /dev/null
+++ b/src/main/java/com/example/payment/PaymentApiResponse.java
@@ -0,0 +1,4 @@
+package com.example.payment;
+
+public record PaymentApiResponse(boolean success) {
+}
diff --git a/src/main/java/com/example/payment/PaymentProcessor.java b/src/main/java/com/example/payment/PaymentProcessor.java
index 137bab7d9..de22a6562 100644
--- a/src/main/java/com/example/payment/PaymentProcessor.java
+++ b/src/main/java/com/example/payment/PaymentProcessor.java
@@ -1,23 +1,32 @@
package com.example.payment;
-//public class PaymentProcessor {
-// private static final String API_KEY = "sk_test_123456";
-//
-// public boolean processPayment(double amount) {
-// // Anropar extern betaltjänst direkt med statisk API-nyckel
-// PaymentApiResponse response = PaymentApi.charge(API_KEY, amount);
-//
-// // Skriver till databas direkt
-// if (response.isSuccess()) {
-// DatabaseConnection.getInstance()
-// .executeUpdate("INSERT INTO payments (amount, status) VALUES (" + amount + ", 'SUCCESS')");
-// }
-//
-// // Skickar e-post direkt
-// if (response.isSuccess()) {
-// EmailService.sendPaymentConfirmation("user@example.com", amount);
-// }
-//
-// return response.isSuccess();
-// }
-//}
+public class PaymentProcessor {
+ private static final String API_KEY = "sk_test_123456";
+ private final DatabaseConnection databaseConnection;
+ private final EmailService emailService;
+ private final PaymentApi paymentApi;
+
+ public PaymentProcessor(DatabaseConnection databaseConnection, EmailService emailService, PaymentApi paymentApi) {
+ this.databaseConnection = databaseConnection;
+ this.emailService = emailService;
+ this.paymentApi = paymentApi;
+ }
+
+ public boolean processPayment(double amount) {
+ // Anropar extern betaltjänst direkt med statisk API-nyckel
+ PaymentApiResponse response = this.paymentApi.charge(API_KEY, amount);
+
+ // Skriver till databas direkt
+ if (response.success()) {
+ this.databaseConnection
+ .executeUpdate("INSERT INTO payments (amount, status) VALUES (" + amount + ", 'SUCCESS')");
+ }
+
+ // Skickar e-post direkt
+ if (response.success()) {
+ emailService.sendPaymentConfirmation("user@example.com", amount);
+ }
+
+ return response.success();
+ }
+}
diff --git a/src/test/java/com/example/PaymentProcessorTest.java b/src/test/java/com/example/PaymentProcessorTest.java
new file mode 100644
index 000000000..f81bfbeac
--- /dev/null
+++ b/src/test/java/com/example/PaymentProcessorTest.java
@@ -0,0 +1,77 @@
+package com.example;
+
+import com.example.payment.*;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.sql.SQLException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.anyDouble;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+@ExtendWith(MockitoExtension.class)
+class PaymentProcessorTest {
+
+ @Mock
+ private PaymentApi paymentApi;
+
+ @Mock
+ private DatabaseConnection databaseConnection;
+
+ @Mock
+ private EmailService emailService;
+
+ @InjectMocks
+ private PaymentProcessor paymentProcessor;
+
+ @Test
+ @DisplayName("Should return true and save to database when payment is successful")
+ void paymentSuccess() throws SQLException {
+ PaymentApiResponse response = new PaymentApiResponse(true);
+ double amount = 100.0;
+
+ Mockito.when(paymentApi.charge("sk_test_123456", amount)).thenReturn(response);
+ boolean result = paymentProcessor.processPayment(amount);
+
+ assertThat(result).isTrue();
+ verify(databaseConnection).executeUpdate(anyString());
+ }
+
+ @Test
+ @DisplayName("Should send email notification with correct details on success")
+ void sendEmailNotificationWhenPaymentIsSuccessful() throws SQLException {
+ PaymentApiResponse response = new PaymentApiResponse(true);
+ double amount = 100.0;
+ String email = "user@example.com";
+
+ Mockito.when(paymentApi.charge("sk_test_123456", amount)).thenReturn(response);
+ boolean result = paymentProcessor.processPayment(amount);
+
+ assertThat(result).isTrue();
+ verify(databaseConnection).executeUpdate(anyString());
+ verify(emailService).sendPaymentConfirmation(email, amount);
+ }
+
+ @Test
+ @DisplayName("Should return false and perform no side effects when payment fails")
+ void paymentFails() throws SQLException {
+ PaymentApiResponse response = new PaymentApiResponse(false);
+ double amount = 100.0;
+
+ Mockito.when(paymentApi.charge("sk_test_123456", amount)).thenReturn(response);
+ boolean result = paymentProcessor.processPayment(amount);
+
+ assertThat(result).isFalse();
+ verify(databaseConnection, never()).executeUpdate(anyString());
+ verify(emailService, never()).sendPaymentConfirmation(anyString(), anyDouble());
+ }
+
+}