add test project

This commit is contained in:
Oli Sturm
2026-04-22 15:17:44 +01:00
parent 87907539cb
commit 778e181ed1
4 changed files with 177 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
using CsharpFp2.Domain;
namespace CsharpFp2.Tests;
/// Tests covering domain-layer invariants on the Account aggregate directly,
/// independent of the application layer.
public class AccountTests
{
[Fact]
public void Opening_an_account_with_a_negative_balance_throws()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
new Account(new AccountId(Guid.NewGuid()), new Money(-1m))
);
}
[Fact]
public void Withdrawing_a_zero_amount_throws()
{
var account = new Account(new AccountId(Guid.NewGuid()), new Money(100m));
Assert.Throws<InvalidOperationException>(() => account.Withdraw(new Money(0m)));
}
[Fact]
public void Withdrawing_a_negative_amount_throws()
{
var account = new Account(new AccountId(Guid.NewGuid()), new Money(100m));
Assert.Throws<InvalidOperationException>(() => account.Withdraw(new Money(-10m)));
}
[Fact]
public void Withdrawing_more_than_the_balance_throws()
{
var account = new Account(new AccountId(Guid.NewGuid()), new Money(100m));
Assert.Throws<InsufficientBalanceException>(() => account.Withdraw(new Money(101m)));
}
[Fact]
public void Successive_withdrawals_are_each_applied_to_the_running_balance()
{
var account = new Account(new AccountId(Guid.NewGuid()), new Money(300m));
account.Withdraw(new Money(100m));
account.Withdraw(new Money(100m));
Assert.Equal(100m, account.Balance.Amount);
}
}
@@ -0,0 +1,85 @@
using CsharpFp2.Applications;
using CsharpFp2.Contracts;
using CsharpFp2.Domain;
using CsharpFp2.Infrastructure;
namespace CsharpFp2.Tests;
/// Tests covering the application-layer use case surface:
/// what the WithdrawMoney feature does from the caller's perspective.
public class WithdrawMoneyHandlerTests
{
private static (
WithdrawMoneyHandler handler,
InMemoryAccountRepository repository
) BuildHandler()
{
var repository = new InMemoryAccountRepository();
var handler = new WithdrawMoneyHandler(repository);
return (handler, repository);
}
[Fact]
public void Withdrawing_from_an_account_reduces_its_balance_by_the_withdrawn_amount()
{
var (handler, repository) = BuildHandler();
var accountId = Guid.NewGuid();
repository.Save(new Account(new AccountId(accountId), new Money(200m)));
handler.Handle(new WithdrawMoneyCommand { AccountId = accountId, Amount = 75m });
var account = repository.GetById(new AccountId(accountId))!;
Assert.Equal(125m, account.Balance.Amount);
}
[Fact]
public void Withdrawing_the_entire_balance_leaves_the_account_at_zero()
{
var (handler, repository) = BuildHandler();
var accountId = Guid.NewGuid();
repository.Save(new Account(new AccountId(accountId), new Money(100m)));
handler.Handle(new WithdrawMoneyCommand { AccountId = accountId, Amount = 100m });
var account = repository.GetById(new AccountId(accountId))!;
Assert.Equal(0m, account.Balance.Amount);
}
[Fact]
public void Withdrawing_from_a_non_existent_account_throws()
{
var (handler, _) = BuildHandler();
var command = new WithdrawMoneyCommand { AccountId = Guid.NewGuid(), Amount = 50m };
Assert.Throws<InvalidOperationException>(() => handler.Handle(command));
}
[Fact]
public void Withdrawing_more_than_the_available_balance_throws()
{
var (handler, repository) = BuildHandler();
var accountId = Guid.NewGuid();
repository.Save(new Account(new AccountId(accountId), new Money(50m)));
Assert.Throws<InsufficientBalanceException>(() =>
handler.Handle(new WithdrawMoneyCommand { AccountId = accountId, Amount = 100m })
);
}
[Fact]
public void After_a_failed_withdrawal_the_balance_is_unchanged()
{
var (handler, repository) = BuildHandler();
var accountId = Guid.NewGuid();
repository.Save(new Account(new AccountId(accountId), new Money(50m)));
try
{
handler.Handle(new WithdrawMoneyCommand { AccountId = accountId, Amount = 999m });
}
catch (InsufficientBalanceException) { }
var account = repository.GetById(new AccountId(accountId))!;
Assert.Equal(50m, account.Balance.Amount);
}
}
+26
View File
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>CsharpFp2.Tests</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\csharp-fp2\csharp-fp2.csproj" />
</ItemGroup>
</Project>