BankCoreSolution: The Bank App Built to Teach You How to Break It, Then Prove It Works

A cleanly separated .NET banking system that turns MSTest, NUnit, xUnit, and formal test documentation into one connected training ground.

8 min read • View on GitHub • More from SRougee

A banking vault split open to reveal a testing lab inside. Ledgers, coins, and account slips sit on one side, while test scripts, checklists, a magnifying glass, and a defect tag pinned to a ledger page occupy the other. It explains that the banking app is just the wrapper and that verification is the real subject.
The bank is the costume. The testing lab is the engine.
Key Takeaways

This Bank Exists to Be Tested

BankCoreSolution is not trying to look like a real bank product. It is trying to behave like a controlled lab where banking actions become test cases, defects become teaching material, and evidence is treated as a first-class artifact.

That is why the repo is interesting. The domain is familiar enough to understand quickly, but the structure around it is what matters: clean boundaries, deliberate bugs, three test frameworks, and documentation that lives beside the code instead of behind it.

The result feels less like a CRUD tutorial and more like a proof-of-correctness machine. You can trace a withdrawal from UI to service logic to test coverage to a defect log.


The Real Product Is the Testing Workflow

The same transaction is examined by several lenses, and each lens leaves behind evidence.

The repo’s core idea is simple: correctness is not asserted once. It is observed from several angles. The validation layer checks input, the business layer enforces account rules, the audit layer records what happened, and the test stack probes each checkpoint differently.

LayerWhat it doesWhy it matters
ValidationChecks fields, roles, and basic input shapeStops bad requests before business logic has to reason about them
Business rulesApplies account limits, balances, and transfer rulesDefines what the system is allowed to do
AuditRecords events and outcomesCreates a trail you can inspect after the fact
Test docsMaps requirements, defects, and coverageTurns verification into an accountable process

That is a much stronger teaching model than a monolithic demo app. Instead of saying 'here is a bank,' it says 'here is how a system proves that a bank action is valid, correct, and traceable.'

Inside the Core: A Clean Boundary Around Business Rules

The architecture is intentionally restrained. BankCore.Core holds the models, interfaces, and services. BankCore.Data provides in-memory repositories. BankCore.App is a thin console shell that wires everything together with manual dependency injection.

// Simplified shape of the flow
var validation = new ValidationService();
var audit = new AuditService();
var repo = new InMemoryAccountRepository();
var accountService = new AccountService(validation, repo, audit);

var result = accountService.Withdraw(accountId, 200m);

That manual wiring matters. It keeps the domain logic easy to interrogate because the business service is not hiding behind a web framework, a persistence framework, or a dependency injection container that obscures the edges.

A mechanical pipeline sends one account action through validation gates, business rule gears, and an audit stamp station. Three parallel inspection booths labeled MSTest, NUnit, and xUnit watch different checkpoints, while defect log, traceability matrix, and coverage report sit at the end. It explains how one domain action is verified through several lenses.
Three frameworks do not duplicate the same job here. They observe different checkpoints.

Why Three Test Frameworks Instead of One

This is not framework fan fiction. The split is pedagogical. MSTest, NUnit, and xUnit are used to show that the same codebase can support different testing habits and different kinds of assertions without collapsing into one generic style.

FrameworkBest fit in this repoWhat it teaches
MSTestRole checks and straightforward coverageHow to express reliable baseline verification
NUnitDecision-table style behavior and reversalsHow to organize branching logic and scenarios
xUnitTheory-driven calculations and rulesHow to keep data-driven tests concise

That arrangement makes the test suite feel intentional. It also makes a subtle point: framework choice is not just syntax. It is a way of shaping how you think about the behavior under test.

The Hidden Curriculum in the Test Docs

The most unusual part of the repo may be the documentation folder. Risk registers, defect logs, traceability matrices, and coverage reports are not side quests here. They are part of the system’s verification story.

That changes the tone completely. Testing stops being a CI checkbox and starts looking like a discipline with evidence, lineage, and accountability.

It also makes the repository more useful for teaching. A learner can move from requirement to test case to defect to coverage artifact and see how the whole chain fits together.

A formal trail from requirement to evidence

When a defect is logged, it is not just a bug note. It becomes a hinge between the code, the tests, and the documentation. That is a stronger habit than simply checking whether the suite is green.

What the Intentional Bugs Teach

The explicit bug markers, including BUG-005, are the clearest sign that this repo is meant for investigation. A hidden defect would make the exercise feel like ordinary debugging. A labeled defect turns the codebase into a guided exercise in test design.

// BUG-005: Daily withdrawal limit is set to initial deposit
// This is intentional for the learning setup and should be caught by tests.

That kind of comment does two things at once. It makes the failure legible, and it forces the reader to think about how a test should expose it. The lesson is not just that bugs exist. The lesson is that a good test suite should tell you where the model of the system breaks.

Why This Pattern Scales Better Than a Typical Demo App

A conventional tutorial app usually optimizes for speed of understanding. BankCoreSolution optimizes for depth of verification. That makes it a better training ground for developers who need to reason about systems, not just features.

DimensionTypical demo backendBankCoreSolution
Domain logicPresent, but mostly illustrativeIsolated and easy to interrogate
Test strategyOften one framework, one styleThree frameworks with distinct roles
DocumentationLightweight or absentTraceability, defects, and coverage are explicit
Fault discoveryUsually accidentalDeliberate and teachable
Educational valueShows how to buildShows how to prove it works

That is the real differentiator. The repo trains a habit of thinking in systems. Behavior is not just implemented. It is validated, documented, and made inspectable.