<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3" -->

---
title: How to Build Characterization Tests Before Refactoring...
description: A practical tutorial on characterization testing, a technique for capturing what legacy code currently does before refactoring it, rather than what it should...
canonical: https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: How to Build Characterization Tests Before Refactoring Legacy Code | daily.dev
og:description: A practical tutorial on characterization testing, a technique for capturing what legacy code currently does before refactoring it, rather than what it should...
og:url: https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3
og:image: https://api.daily.dev/og/posts/5jWK11Sf3.png
og:image:alt: How to Build Characterization Tests Before Refactoring Legacy Code
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Build Characterization Tests Before Refactoring Legacy Code

**[freeCodeCamp](https://daily.dev/sources/freecodecamp)** · 18 min read · 1 upvotes · 1 comments

## Summary

A practical tutorial on characterization testing, a technique for capturing what legacy code currently does before refactoring it, rather than what it should do. It covers identifying observable behavior worth protecting, choosing test boundaries, handling side effects, databases, and external services, and using AI carefully to discover candidate tests without letting it invent expected business rules. Examples use TypeScript and Vitest, but the approach generalizes across languages. The piece closes with a ten-step workflow for applying characterization tests during incremental refactors.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.freecodecamp.org/news/characterization-tests-before-refactoring-legacy-code>

## Questions this post answers

### What is a characterization test and how is it different from a normal unit test?

A characterization test documents what code currently does rather than what it should do. Unlike typical tests that express intended behavior, characterization tests capture existing observable outputs, side effects, and external calls of legacy code so a refactor can be verified against a baseline instead of assumptions about correct behavior.

_daily.dev surfaces testing patterns like this for developers modernizing legacy systems._

### How should I prompt an AI assistant to help find characterization tests without it making up expected values?

Ask the AI to analyze the class without changing it, group observable behaviors into categories like returned values, state changes, persistence effects, external calls, emitted events, exceptions, and boundary conditions, and explicitly instruct it not to invent expected values or propose results unless derived from executable behavior or existing tests.

_developers combining AI with legacy refactoring can find prompt techniques like this on daily.dev._

### What is a good strategy for testing legacy code that depends directly on a database?

Two options work: run an integration test against a disposable test database when the database behavior itself matters, or introduce a seam by extracting a repository interface (like findById/update) so the function can be tested without hitting the real database, keeping this structural change purely mechanical before any behavior refactor.

_engineers untangling database-coupled legacy code can track approaches like this on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@leonidbugaev** · 0 upvotes

> The 65 vs 66 discount is the one I'd actually run. I've had the model write expect(calculateDiscount(65)).toBe(0.2) off that if, and that's not what the code does.

## Similar posts on daily.dev

- [A Testing Strategy for Legacy Modernisation \| Insights](https://daily.dev/posts/a-testing-strategy-for-legacy-modernisation-insights-bckoasyqj) · Dev Genius · 0 upvotes · 0 comments

---

Tags: [#typescript](https://daily.dev/tags/typescript), [#vitest](https://daily.dev/tags/vitest)

[View this post on daily.dev](https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"How to Build Characterization Tests Before Refactoring Legacy Code","url":"https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3"},"datePublished":"2026-08-31T22:12:29.108Z","dateModified":"2026-09-14T06:19:49.183Z","description":"A practical tutorial on characterization testing, a technique for capturing what legacy code currently does before refactoring it, rather than what it should...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/da9268da84ab98cb2023d36218bad0f8?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/da9268da84ab98cb2023d36218bad0f8?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"freeCodeCamp","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"freeCodeCamp","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1628412854/logos/freecodecamp","url":"https://daily.dev/sources/freecodecamp"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"typescript,vitest","timeRequired":"PT18M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"freeCodeCamp","item":"https://daily.dev/sources/freecodecamp"},{"@type":"ListItem","position":3,"name":"How to Build Characterization Tests Before Refactoring Legacy Code"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3","comment":[{"@type":"Comment","text":"The 65 vs 66 discount is the one I’d actually run. I’ve had the model write expect(calculateDiscount(65)).toBe(0.2) off that if, and that’s not what the code does.","datePublished":"2026-09-01T03:09:05.934Z","url":"https://daily.dev/posts/5jWK11Sf3#c-UO9s91baN","author":{"@type":"Person","name":"Leonid Bugaev","url":"https://daily.dev/leonidbugaev","image":"https://lh3.googleusercontent.com/a/ACg8ocLhMgurwTmJElWaH9A8Ju8cHvZxgMCDt009jEYkmFCyUGAoaGSw=s96-c"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/how-to-build-characterization-tests-before-refactoring-legacy-code-5jwk11sf3#faq","mainEntity":[{"@type":"Question","name":"What is a characterization test and how is it different from a normal unit test?","acceptedAnswer":{"@type":"Answer","text":"A characterization test documents what code currently does rather than what it should do. Unlike typical tests that express intended behavior, characterization tests capture existing observable outputs, side effects, and external calls of legacy code so a refactor can be verified against a baseline instead of assumptions about correct behavior. daily.dev surfaces testing patterns like this for developers modernizing legacy systems."}},{"@type":"Question","name":"How should I prompt an AI assistant to help find characterization tests without it making up expected values?","acceptedAnswer":{"@type":"Answer","text":"Ask the AI to analyze the class without changing it, group observable behaviors into categories like returned values, state changes, persistence effects, external calls, emitted events, exceptions, and boundary conditions, and explicitly instruct it not to invent expected values or propose results unless derived from executable behavior or existing tests. developers combining AI with legacy refactoring can find prompt techniques like this on daily.dev."}},{"@type":"Question","name":"What is a good strategy for testing legacy code that depends directly on a database?","acceptedAnswer":{"@type":"Answer","text":"Two options work: run an integration test against a disposable test database when the database behavior itself matters, or introduce a seam by extracting a repository interface (like findById/update) so the function can be tested without hitting the real database, keeping this structural change purely mechanical before any behavior refactor. engineers untangling database-coupled legacy code can track approaches like this on daily.dev."}}]}
```

