The Uncomfortable Truth Nobody Wants to Hear

Let me start with something that will make your Twitter timeline combust: junior developers writing tests is like letting someone learn to drive by driving a school bus during rush hour. Sure, they’ll probably survive, and maybe even learn something. But is that really the best use of everyone’s time and sanity? I can already hear the collective gasp from the test-driven development zealots, the agile evangelists, and the “everyone should code review everything” crowd. But hear me out—this isn’t about gatekeeping for the sake of gatekeeping. This is about recognizing that there’s a fundamental skill hierarchy in software development that we’ve been desperately trying to flatten, and it’s costing us more than we realize.

The Uncomfortable Hierarchy Nobody Talks About

Here’s the thing: testing is hard. Not “hard” in the way that learning your first programming language is hard. Testing is hard in the way that writing good test cases requires understanding not just how code works, but why it might fail. It requires pattern recognition that only comes from seeing hundreds of failure modes. It requires the kind of systems thinking that junior developers are still developing. When we insist that junior developers write tests from day one, we’re asking them to do something that requires:

  • Deep understanding of the codebase they’re still learning
  • Awareness of edge cases they haven’t encountered yet
  • Experience with failure modes they haven’t seen
  • The maturity to write tests that won’t become technical debt in six months We’re essentially asking someone who just learned to use a hammer to design a bridge.

What the Data Actually Tells Us (and What We Ignore)

Research in developer testing practices reveals something uncomfortable: when developers write tests, they tend to focus on the “happy path.” They’re four times more likely to write tests demonstrating features work than tests attempting to provoke failures. This bias exists in experienced developers—imagine the damage it does when amplified by junior developers who haven’t learned to think like an attacker yet. Junior developers are also more likely to:

  • Write shallow test cases that give false confidence
  • Create brittle tests that break with refactoring
  • Miss edge cases and error handling scenarios
  • Create test suites that are themselves buggy (yes, tests can have bugs)
  • Document their test cases poorly, making maintenance harder These aren’t moral failings. They’re developmental stages. But we’ve decided to ignore them anyway.

The Real Cost of “Everyone Tests”

Let’s talk about opportunity cost, because that’s what management actually cares about (even if they don’t say it). When you assign a junior developer to write tests, here’s what actually happens: Junior Developer’s Time Breakdown:

  • 40% writing the actual test code
  • 30% debugging why the test doesn’t work
  • 20% trying to understand what they’re supposed to test
  • 10% actual learning about the codebase A senior engineer writing the same test suite:
  • 50% writing the test code (because they know what they’re doing)
  • 20% debugging
  • 20% architectural thinking
  • 10% documenting patterns for the future The senior engineer produces better tests in less time. But instead, we have junior developers spending three hours writing tests that a senior engineer would write in 45 minutes.

The Real Problem Masquerading as a Solution

The philosophy of “everyone should write tests because testing is important” is like saying “everyone should cook dinner because eating is important.” Technically true, but practically ridiculous. What we’ve actually created is a system where:

  1. Junior developers write weak tests that create false confidence
  2. These weak tests become institutional because nobody has time to rewrite them
  3. The codebase becomes harder to refactor because you can’t change code without breaking ten fragile test assertions
  4. Senior engineers spend time fixing tests instead of mentoring or architecting
  5. Testing becomes something junior developers tolerate rather than something they understand This is how you turn “testing is important” into “testing is a chore.” And once testing becomes a chore, you’re finished. You’ve lost the war.

What Should Actually Happen (The Radical Proposal)

Here’s where I lose half my audience: junior developers should focus on writing good code, not writing tests. I know. Wild. Controversial. Possibly career-ending to suggest. But think about it differently. If a junior developer ships code that is:

  • Clear and readable
  • Well-structured
  • Properly documented
  • Follows established patterns
  • Has obvious boundaries and responsibilities Then testing that code is easy. A mid-level or senior engineer can write comprehensive tests in a fraction of the time. Conversely, if code is convoluted, poorly documented, and breaks design patterns? No amount of testing by a junior developer will fix that. They’ll just write convoluted tests. The hierarchy should look like this:
Code Quality (Primary responsibility: Junior Developers)
    ↓
Test Design (Primary responsibility: Mid-level Developers)
    ↓
Test Architecture (Primary responsibility: Senior Developers)

Not this mess we have now:

Code Quality (Shared)
Test Writing (Shared)
Test Maintenance (Shared)
Everyone confused (Everyone)

The QA Versus Developer Testing False Dichotomy

We’ve also created this weird situation where QA teams exist to “catch what developers miss,” but we simultaneously insist that developers write tests. So what’s QA doing? And if QA is doing testing, why do developers also need to test? This confusion exists because we’ve never been clear about skill levels. A dedicated QA professional, especially a junior QA specialist, spends their entire working day understanding:

  • How to design test cases from requirements
  • How to identify bugs systematically
  • How to perform regression testing
  • How to document defects properly They’re developing testing expertise. Meanwhile, junior developers are supposed to become testing experts in addition to becoming development experts. It’s cognitively overloaded. Here’s the uncomfortable truth: testing is its own discipline. We’ve been pretending it isn’t, and the quality of our tests (and consequently our code) has suffered.

When Junior Developers Do Touch Tests (The Right Way)

Now, I’m not saying junior developers should never write tests. That would be absurd. They should, but in controlled conditions:

1. Only After Pairing

A junior developer should only write tests after sitting with someone experienced and understanding:

  • Why those specific assertions matter
  • What edge cases exist
  • What patterns to follow
  • Why certain approaches fail This takes time. That’s the point.

2. Within Guardrails

Before a junior developer writes a test, there should be:

  • A documented test pattern they’re following
  • Clear examples they can reference
  • Explicit acceptance criteria for what makes a test “good”
  • A checklist they complete before submission

3. Always Code Reviewed by Specialists

Tests should be reviewed by people who know testing deeply, not just by “any senior engineer who has time.” This means either:

  • Dedicated QA specialists reviewing test code
  • Senior engineers with testing expertise doing the review
  • Testing architects setting standards Not: “whatever senior developer is around.”

A Practical Example: The Right Way vs. The Wrong Way

Let’s say you have a payment processing function. Here’s what usually happens: The Wrong Way (Current Reality): A junior developer writes:

test('payment should work', () => {
  const result = processPayment(100, 'VISA');
  expect(result.success).toBe(true);
});

Done. Shipped. False confidence secured. The Right Way: A senior engineer first describes what should be tested: “This function needs tests for:

  • Valid payment with valid card
  • Valid payment with expired card
  • Invalid payment amount
  • Network failure during processing
  • Currency conversion edge cases
  • Concurrent payment attempts Here’s the pattern we use for async tests in this codebase…” Then the junior developer, guided, might write:
describe('processPayment', () => {
  describe('valid payments', () => {
    test('should succeed with valid card and amount', async () => {
      const payment = {
        amount: 99.99,
        currency: 'USD',
        cardToken: validCardToken
      };
      const result = await processPayment(payment);
      expect(result.success).toBe(true);
      expect(result.transactionId).toBeDefined();
      expect(result.timestamp).toBeLessThanOrEqual(Date.now());
    });
  });
  describe('error handling', () => {
    test('should reject expired card', async () => {
      const payment = {
        amount: 99.99,
        currency: 'USD',
        cardToken: expiredCardToken
      };
      const result = await processPayment(payment);
      expect(result.success).toBe(false);
      expect(result.error).toBe('CARD_EXPIRED');
    });
  });
});

That’s better. But even then, a specialist would review it and say: “Good start. Now add tests for network failures, currency mismatches, and what happens with amount = 0. Here’s how we mock network calls in this codebase…”

The Mermaid Diagram Nobody Wanted But Everyone Needs

graph TD A["New Junior Developer"] -->|Writes Code| B["Code Review by Senior"] B -->|Approved| C["Code Merged"] C -->|Testing Specialist Reviews| D["Test Suite Created"] D -->|Junior Dev Learns Pattern| E["Next Task Assigned"] F["Current Reality"] -->|Junior Writes Code| G["Junior Writes Tests"] G -->|Quick Code Review| H["Both Ship"] H -->|Six Months Later| I["Tests Failing on Refactor"] I -->|Senior Fixes Tests| J["Technical Debt Accumulates"]

The Uncomfortable Conversation We Need to Have

This all comes down to one thing: we’ve confused “egalitarianism” with “skill equity.” Making sure everyone writes code is great. It’s democratic. It’s fair. But it doesn’t mean everyone writes equally good code. And it certainly doesn’t mean everyone should write good tests. Some people have the temperament for testing. Some don’t. Some learn it quickly. Some take years. The solution isn’t to pretend everyone’s ready to do it equally; the solution is to build a system that:

  1. Recognizes testing as a specialized skill
  2. Develops that skill deliberately and progressively
  3. Doesn’t ask junior developers to be experts in everything
  4. Actually measures test quality, not just test coverage

What Actually Needs to Change

If we’re serious about this, organizations need to: Invest in Testing Specialists: Hire mid-level and senior engineers who love testing. Pay them what they’re worth. Make testing a career path, not a chore. Create Testing Expertise: Establish testing architecture roles. Let someone design the testing strategy instead of letting it evolve randomly. Define Progression: Make it explicit: “Junior developers focus on code quality. Mid-level developers learn to write good tests. Senior developers architect testing systems.” Measure Differently: Stop measuring “code coverage.” Measure “test quality.” Measure “bugs caught per test.” Measure “test maintenance burden.” Let It Take Time: A junior developer becoming a testing expert should take 2-3 years, not 2-3 weeks.

The Bottom Line

Junior developers shouldn’t touch tests because they’re not ready to do them well, and half-measures in testing are worse than no testing at all. A junior developer with good code and no tests is healthier for a codebase than a junior developer with mediocre code and mediocre tests everywhere. This isn’t gatekeeping. It’s specialization. It’s the same reason we don’t let junior architects design load-balancing systems. It’s the same reason we don’t let junior surgeons perform complex procedures. Testing matters. Which is exactly why it’s too important to leave to people still learning their craft. Will this take longer? Initially, yes. Will it cost more? Maybe. Will it feel less “democratic” than having everyone test everything? Absolutely. But you know what it will produce? Code with actually good tests. A codebase that gets better over time instead of accumulating debt. And junior developers who eventually become senior developers who know how to test properly, instead of perpetuating the cycle of mediocre test practices. Sometimes gatekeeping isn’t evil. Sometimes it’s just recognizing that some gates exist for a reason.