From 4b3360dbeeb94665b0b164542d2bc563badb1f8a Mon Sep 17 00:00:00 2001 From: f-regal Date: Fri, 10 Oct 2025 19:11:07 +0100 Subject: [PATCH 1/2] Refactored Project to use SOLID principles + added unit tests --- .../ClearBank.DeveloperTest.Tests.csproj | 6 ++ .../Tests/ExampleTests.cs | 13 ++++ .../Tests/PaymentServiceTests.cs | 73 +++++++++++++++++++ .../Data/AccountDataStore.cs | 2 +- .../Data/AccountDataStoreFactory.cs | 17 +++++ .../Data/BackupAccountDataStore.cs | 2 +- .../Data/IAccountDataStore.cs | 10 +++ .../Data/IAccountDataStoreFactory.cs | 7 ++ .../Services/PaymentService.cs | 67 +++++------------ 9 files changed, 146 insertions(+), 51 deletions(-) create mode 100644 ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs create mode 100644 ClearBank.DeveloperTest.Tests/Tests/PaymentServiceTests.cs create mode 100644 ClearBank.DeveloperTest/Data/AccountDataStoreFactory.cs create mode 100644 ClearBank.DeveloperTest/Data/IAccountDataStore.cs create mode 100644 ClearBank.DeveloperTest/Data/IAccountDataStoreFactory.cs diff --git a/ClearBank.DeveloperTest.Tests/ClearBank.DeveloperTest.Tests.csproj b/ClearBank.DeveloperTest.Tests/ClearBank.DeveloperTest.Tests.csproj index b21ab73..bc0ae4b 100644 --- a/ClearBank.DeveloperTest.Tests/ClearBank.DeveloperTest.Tests.csproj +++ b/ClearBank.DeveloperTest.Tests/ClearBank.DeveloperTest.Tests.csproj @@ -3,10 +3,16 @@ net8.0 true + true + + + + + \ No newline at end of file diff --git a/ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs b/ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs new file mode 100644 index 0000000..1047af4 --- /dev/null +++ b/ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs @@ -0,0 +1,13 @@ +using Xunit; + +namespace ClearBank.DeveloperTest.Tests +{ + public class ExampleTests + { + [Fact] + public void SampleTest_Passes() + { + Assert.True(true); + } + } +} diff --git a/ClearBank.DeveloperTest.Tests/Tests/PaymentServiceTests.cs b/ClearBank.DeveloperTest.Tests/Tests/PaymentServiceTests.cs new file mode 100644 index 0000000..cbd9524 --- /dev/null +++ b/ClearBank.DeveloperTest.Tests/Tests/PaymentServiceTests.cs @@ -0,0 +1,73 @@ +using ClearBank.DeveloperTest.Data; +using ClearBank.DeveloperTest.Services; +using ClearBank.DeveloperTest.Types; +using System; +using Xunit; + +namespace ClearBank.DeveloperTest.Tests +{ + public class PaymentServiceTests + { + private class FakeStore : IAccountDataStore + { + public Account Account { get; set; } + + public Account GetAccount(string accountNumber) => Account; + + public void UpdateAccount(Account account) => Account = account; + } + + private class FakeFactory : IAccountDataStoreFactory + { + public FakeStore Store { get; } = new FakeStore(); + + public IAccountDataStore Create(string type) => Store; + } + + [Fact] + public void Bacs_Fails_When_Account_Null() + { + var factory = new FakeFactory(); + factory.Store.Account = null; + + var svc = new PaymentService(factory); + + var req = new MakePaymentRequest { DebtorAccountNumber = "123", Amount = 10m, PaymentScheme = PaymentScheme.Bacs }; + + var result = svc.MakePayment(req); + + Assert.False(result.Success); + } + + [Fact] + public void FasterPayments_Fails_When_Insufficient_Balance() + { + var factory = new FakeFactory(); + factory.Store.Account = new Account { AccountNumber = "123", Balance = 5m, AllowedPaymentSchemes = AllowedPaymentSchemes.FasterPayments }; + + var svc = new PaymentService(factory); + + var req = new MakePaymentRequest { DebtorAccountNumber = "123", Amount = 10m, PaymentScheme = PaymentScheme.FasterPayments }; + + var result = svc.MakePayment(req); + + Assert.False(result.Success); + } + + [Fact] + public void Chaps_Succeeds_When_Live_And_Allowed() + { + var factory = new FakeFactory(); + factory.Store.Account = new Account { AccountNumber = "123", Balance = 100m, AllowedPaymentSchemes = AllowedPaymentSchemes.Chaps, Status = AccountStatus.Live }; + + var svc = new PaymentService(factory); + + var req = new MakePaymentRequest { DebtorAccountNumber = "123", Amount = 10m, PaymentScheme = PaymentScheme.Chaps }; + + var result = svc.MakePayment(req); + + Assert.True(result.Success); + Assert.Equal(90m, factory.Store.Account.Balance); + } + } +} diff --git a/ClearBank.DeveloperTest/Data/AccountDataStore.cs b/ClearBank.DeveloperTest/Data/AccountDataStore.cs index 89e49dd..a2b8360 100644 --- a/ClearBank.DeveloperTest/Data/AccountDataStore.cs +++ b/ClearBank.DeveloperTest/Data/AccountDataStore.cs @@ -2,7 +2,7 @@ namespace ClearBank.DeveloperTest.Data { - public class AccountDataStore + public class AccountDataStore : IAccountDataStore { public Account GetAccount(string accountNumber) { diff --git a/ClearBank.DeveloperTest/Data/AccountDataStoreFactory.cs b/ClearBank.DeveloperTest/Data/AccountDataStoreFactory.cs new file mode 100644 index 0000000..4c95b7c --- /dev/null +++ b/ClearBank.DeveloperTest/Data/AccountDataStoreFactory.cs @@ -0,0 +1,17 @@ +using System.Configuration; + +namespace ClearBank.DeveloperTest.Data +{ + public class AccountDataStoreFactory : IAccountDataStoreFactory + { + public IAccountDataStore Create(string type) + { + if (type == "Backup") + { + return new BackupAccountDataStore(); + } + + return new AccountDataStore(); + } + } +} diff --git a/ClearBank.DeveloperTest/Data/BackupAccountDataStore.cs b/ClearBank.DeveloperTest/Data/BackupAccountDataStore.cs index 170362c..d00fbaa 100644 --- a/ClearBank.DeveloperTest/Data/BackupAccountDataStore.cs +++ b/ClearBank.DeveloperTest/Data/BackupAccountDataStore.cs @@ -2,7 +2,7 @@ namespace ClearBank.DeveloperTest.Data { - public class BackupAccountDataStore + public class BackupAccountDataStore : IAccountDataStore { public Account GetAccount(string accountNumber) { diff --git a/ClearBank.DeveloperTest/Data/IAccountDataStore.cs b/ClearBank.DeveloperTest/Data/IAccountDataStore.cs new file mode 100644 index 0000000..258ad77 --- /dev/null +++ b/ClearBank.DeveloperTest/Data/IAccountDataStore.cs @@ -0,0 +1,10 @@ +using ClearBank.DeveloperTest.Types; + +namespace ClearBank.DeveloperTest.Data +{ + public interface IAccountDataStore + { + Account GetAccount(string accountNumber); + void UpdateAccount(Account account); + } +} diff --git a/ClearBank.DeveloperTest/Data/IAccountDataStoreFactory.cs b/ClearBank.DeveloperTest/Data/IAccountDataStoreFactory.cs new file mode 100644 index 0000000..428497b --- /dev/null +++ b/ClearBank.DeveloperTest/Data/IAccountDataStoreFactory.cs @@ -0,0 +1,7 @@ +namespace ClearBank.DeveloperTest.Data +{ + public interface IAccountDataStoreFactory + { + IAccountDataStore Create(string type); + } +} diff --git a/ClearBank.DeveloperTest/Services/PaymentService.cs b/ClearBank.DeveloperTest/Services/PaymentService.cs index 573713d..9aba5b0 100644 --- a/ClearBank.DeveloperTest/Services/PaymentService.cs +++ b/ClearBank.DeveloperTest/Services/PaymentService.cs @@ -6,65 +6,44 @@ namespace ClearBank.DeveloperTest.Services { public class PaymentService : IPaymentService { + private readonly IAccountDataStoreFactory _factory; + + // Default constructor preserves original behavior + public PaymentService() : this(new AccountDataStoreFactory()) { } + + // Allow injection for testability + public PaymentService(IAccountDataStoreFactory factory) + { + _factory = factory; + } + public MakePaymentResult MakePayment(MakePaymentRequest request) { var dataStoreType = ConfigurationManager.AppSettings["DataStoreType"]; - Account account = null; + var accountStore = _factory.Create(dataStoreType); + var account = accountStore.GetAccount(request.DebtorAccountNumber); - if (dataStoreType == "Backup") - { - var accountDataStore = new BackupAccountDataStore(); - account = accountDataStore.GetAccount(request.DebtorAccountNumber); - } - else - { - var accountDataStore = new AccountDataStore(); - account = accountDataStore.GetAccount(request.DebtorAccountNumber); - } - - var result = new MakePaymentResult(); + var result = new MakePaymentResult { Success = true }; - result.Success = true; - switch (request.PaymentScheme) { case PaymentScheme.Bacs: - if (account == null) - { - result.Success = false; - } - else if (!account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.Bacs)) + if (account == null || !account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.Bacs)) { result.Success = false; } break; case PaymentScheme.FasterPayments: - if (account == null) - { - result.Success = false; - } - else if (!account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.FasterPayments)) - { - result.Success = false; - } - else if (account.Balance < request.Amount) + if (account == null || !account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.FasterPayments) || account.Balance < request.Amount) { result.Success = false; } break; case PaymentScheme.Chaps: - if (account == null) - { - result.Success = false; - } - else if (!account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.Chaps)) - { - result.Success = false; - } - else if (account.Status != AccountStatus.Live) + if (account == null || !account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.Chaps) || account.Status != AccountStatus.Live) { result.Success = false; } @@ -74,17 +53,7 @@ public MakePaymentResult MakePayment(MakePaymentRequest request) if (result.Success) { account.Balance -= request.Amount; - - if (dataStoreType == "Backup") - { - var accountDataStore = new BackupAccountDataStore(); - accountDataStore.UpdateAccount(account); - } - else - { - var accountDataStore = new AccountDataStore(); - accountDataStore.UpdateAccount(account); - } + accountStore.UpdateAccount(account); } return result; From 05b4a08df49934858aa5472f7750adeda2459f27 Mon Sep 17 00:00:00 2001 From: f-regal Date: Tue, 14 Oct 2025 23:35:57 +0100 Subject: [PATCH 2/2] remove unused test --- ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs diff --git a/ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs b/ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs deleted file mode 100644 index 1047af4..0000000 --- a/ClearBank.DeveloperTest.Tests/Tests/ExampleTests.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Xunit; - -namespace ClearBank.DeveloperTest.Tests -{ - public class ExampleTests - { - [Fact] - public void SampleTest_Passes() - { - Assert.True(true); - } - } -}