Clients sometimes flinch when they see "test scaffolding" on a sprint estimate. It looks like overhead — code that doesn't ship a feature, doesn't move a metric, doesn't impress investors. We get it.

But untested code is a draft. And we've seen too many "launches" become three-month bug-fix marathons because nobody agreed on what "done" meant before the first line shipped. Uboraschool taught us this the hard way.

1. Tests define the contract

Before we build a patient intake flow, we write tests that describe the behaviour: valid NHIF numbers pass, duplicate national IDs are rejected, offline submissions queue locally. These tests fail — because nothing is built yet. That's the point.

The test file becomes a shared spec between us and the client. No ambiguity about edge cases. No "I assumed it would work differently" in week six.

test('rejects duplicate national ID', async () => {
  await createPatient({ nationalId: '12345678' });
  await expect(createPatient({ nationalId: '12345678' }))
    .rejects.toThrow('DUPLICATE_NATIONAL_ID');
});

2. Speed comes later, not now

Test-first feels slower on day one. By week three, it's faster. Every regression is caught in CI, not in a WhatsApp message from a clinic manager at 7am. Every refactor is confident. Every handover includes a safety net.

We don't write tests to prove code works. We write tests so we can change code without fear.

3. What we actually test

We're pragmatic, not dogmatic. We don't chase 100% coverage on UI boilerplate. We do test:

  • Business logic — pricing rules, eligibility checks, permission boundaries
  • Integration points — payment webhooks, sync pipelines, API contracts
  • Regression cases — every bug that reaches production gets a test before the fix merges

We skip testing framework internals, generated code, and one-line getters. Your invoice reflects judgment, not checkbox compliance.

4. How we bill for it

Test scaffolding is a line item because it's real work that saves real money. We estimate it upfront — typically 15–25% of feature development time, depending on complexity. Clients who've been burned by rewrite cycles understand the math. Those who haven't yet usually learn within one project.

We also don't bill for fixing bugs that our tests should have caught. If a test gap lets something slip, that's on us.

The studio standard

Every MosesCodes project ships with CI that blocks merges on failing tests. Every handover includes instructions for running the suite locally. And every new feature starts with a failing test — not a screenshot mockup.

Want a team that treats quality as a deliverable, not an afterthought? Let's talk about your next build.