using System.Collections.Generic;
using System.Threading.Tasks;
public static class BankSample
public static BankDbContext Database { get; } = new BankDbContext();
public static async Task Main()
await new BankSampleTests().RunTests();
var owner = new Owner(new Guid());
var checkingAccount = await SetupAccount(owner, BankAccountType.Checking, 325);
var savingsAccount = await SetupAccount(owner, BankAccountType.Checking, 100);
Console.WriteLine(checkingAccount != null && savingsAccount != null
? "Accounts set up successfuly"
: "Error setting up accounts");
private static async Task<IBankAccount> SetupAccount(Owner owner, BankAccountType accountType, double initialDeposit)
throw new ArgumentNullException(nameof(owner));
throw new ArgumentException("initialDeposit {initialDeposit} is less than 0");
BankAccount account = new BankAccount(new Guid(), owner.Id, BankAccountType.Checking);
await account.DepositAsync(initialDeposit);
Console.WriteLine($"Failed to create account with deposit {initialDeposit}. {e.StackTrace}");
public class BankAccount : IBankAccount
public BankAccount(Guid id, Guid ownerId, BankAccountType accountType, double initialBalance = 0)
throw new ArgumentException(nameof(initialBalance), "Amount must be greater than or equal to zero.");
this.AccountType = accountType;
this.Balance = initialBalance;
public async Task<ITransaction> DepositAsync(double amount)
throw new ArgumentException(nameof(amount), "Amount must be greater than zero.");
var transaction = new Transaction(this.OwnerId, this.Id, amount);
await BankSample.Database.Transactions.Add(transaction);
await BankSample.Database.SaveChangesAsync();
public async Task<ITransaction> WithdrawAsync(double amount)
throw new ArgumentException(nameof(amount), "Amount must be greater than zero.");
if (!this.AllowOverdraft && this.Balance + - amount < 0)
throw new OverdraftException(this.Balance - amount);
var transaction = new Transaction(this.OwnerId, this.OwnerId, amount);
await BankSample.Database.Transactions.Add(transaction);
public Guid OwnerId { get; }
public double Balance { get; private set; }
public double InterestRate { get; private set; }
public bool IsOverdrawn => this.Balance < 0;
public bool AllowOverdraft { get; set; }
public BankAccountType AccountType { get; }
public class Transaction : ITransaction
public Transaction(Guid ownerId, Guid accountId, double amount)
this.AccountId = accountId;
public Guid OwnerId { get; }
public Guid AccountId { get; }
public DateTime Time { get; }
public double Amount { get; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public class OverdraftException : Exception
public OverdraftException(double overdraftAmount)
this.OverdraftAmount = overdraftAmount;
public double OverdraftAmount { get; private set; }
public enum BankAccountType
public class BankDbContext
this.BankAccounts = new DbSet<IBankAccount>();
this.Transactions = new DbSet<ITransaction>();
this.Owners = new DbSet<IOwner>();
public DbSet<IBankAccount> BankAccounts { get; private set; }
public DbSet<ITransaction> Transactions { get; private set; }
public DbSet<IOwner> Owners { get; private set; }
public async Task SaveChangesAsync()
public class DbSet<TEntity>
private readonly IList<TEntity> entities = new List<TEntity>();
public async Task Add(TEntity entity)
await Task.Run(() => this.entities.Add(entity));
public interface IBankAccount
double InterestRate { get; }
BankAccountType AccountType { get; }
bool IsOverdrawn { get; }
bool AllowOverdraft { get; set; }
Task<ITransaction> DepositAsync(double amount);
Task<ITransaction> WithdrawAsync(double amount);
public interface ITransaction
string FirstName { get; set; }
string LastName { get; set; }
public class BankSampleTests
public async Task RunTests()
await new BankAccountTests().RunTests();
public class BankAccountTests
public async Task RunTests()
this.Initial_Balance_Test();
this.Deposit_Invalid_Test();
await this.Deposit_Balance_Test();
await this.Deposit_Transaction_Test();
public void Initial_Balance_Test()
var account = new BankAccount(new Guid(), new Guid(), BankAccountType.Savings);
Assert.IsTrue(account.Balance == 0, "Balance is 0");
public void Deposit_Invalid_Test()
var account = new BankAccount(new Guid(), new Guid(), BankAccountType.Savings, -1);
Assert.IsTrue(false, "ArgumentException is expected.");
catch(ArgumentException){
Assert.IsTrue(true, "ArgumentException is caught.");
public async Task Deposit_Balance_Test()
var account = new BankAccount(new Guid(), new Guid(), BankAccountType.Savings);
var depositTransaction = await account.DepositAsync(500);
Assert.IsTrue(account.Balance == 500, "Account balance is 500");
public async Task Deposit_Transaction_Test()
var account = new BankAccount(new Guid(), new Guid(), BankAccountType.Savings);
var depositTransaction = await account.DepositAsync(500);
Assert.IsTrue(depositTransaction.Amount == 500, "Deposit transaction amount is 500");