\u003C/figure>\n\u003C!-- /wp:image -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As we had nearly no unit tests, we had to get moving. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2 id=\"h-why-do-we-need-unit-testing-anyway\">Why do we need unit testing anyway?\u003C/h2>\n\u003C!-- /wp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>You may wonder why we’re adding unit testing now—we’ve made it this far and done pretty well for ourselves, right?\u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As we’ve mentioned, we’re maturing as an engineering organization. We have paid products that large enterprises pay good money for. We have a lot of new tech investment on our roadmap for the next few years, so we’ll need a resilient codebase that lets us refactor code when necessary. To paraphrase, it lets us move fast without breaking things. Plus, refactoring the code for the tests lets us create a baseline of clean code and enforce the “clean beach rule” for future code: leave the code as clean or cleaner than you found it. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Besides the benefits for the code, it makes our overall testing program better and take less time. We used to spend a lot of time on manual regression testing and manual testing during pull request reviews. Automating these tests as unit tests will free up a lot of developer time. And it gets us closer to test-driven development, which will let us continue to ship new features to all three editions of our Stack Overflow for Teams product and our community sites even when those features require changes to existing code. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>A good testing program leads to a better engineering program, so the effort we spend creating unit tests would make our lives easier (and more productive). Clean, well-written tests serve as a form of documentation; you can read through the tests and learn exactly what the associated code is doing. To encourage our engineers to work on test code when they work on product code, we wanted everyone to own the tests themselves, to feel free to change and modify them as needed. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>There were a number of explicit anti-goals we had for this project; results that we were not trying achieve at all. In building out unit tests, we were not trying to create as many tests as possible, or to reach a magical test coverage percentage, or even to follow the testing pyramid strictly. There was no plan to run testing sprints or create tests for existing code en masse or couple tests to implementation. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>In short, we needed to get our code into shape so we could build tests easily, but we weren’t trying to suddenly have test coverage on every piece of code already deployed in production. This is preparation for the future; much of our code has been battle tested by our community of developers. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2 id=\"h-what-we-did\">What we did\u003C/h2>\n\u003C!-- /wp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>In order to create genuine unit tests, we needed to ensure that any piece of functionality could be isolated from its dependencies. And because almost everything that happens on our public sites and Stack Overflow for Teams instances draws data from a database, we needed a way to indicate to tests when to pull mock data. We use both \u003Ca href=\"https://dapperlib.github.io/Dapper/\">Dapper\u003C/a> and \u003Ca href=\"https://docs.microsoft.com/en-us/ef/\">the Entity Framework\u003C/a> within .NET to manage our database connections, so we created an interface that extends \u003Ca href=\"https://docs.microsoft.com/en-us/ef/ef6/fundamentals/working-with-dbcontext\">\u003Ccode>DbContext\u003C/code>\u003C/a> so that we can treat mocked data as a database connection. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Stack Overflow executes a lot of the same queries over and over. As our site was built for speed, we compile a lot of these queries in the Entity Framework. Compiling queries against our \u003Ccode>DbContext\u003C/code> interface was a bit problematic because \u003Ccode>EF.CompileQuery\u003C/code> expects a concrete instance of a \u003Ccode>DbContext\u003C/code>. We came up with a helper class to make it easy for us to use compiled queries when targeting a real database and use in-memory queries when running unit tests. The query stays exactly the same so we know we test the correct behavior. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Once we were able to connect to mock databases, we needed to provide a way to create the mock data that is part of the test. So we introduced a builder that can create mock site data for tests. We’re using builders instead of constructors so we can change how these mock sites are built without having to rewrite all of our unit tests. Builders construct an object by only explicitly passing the information that you need; everything else uses defaults. Again, we did not want to tightly couple our tests and implementation, so we chose to abstract object construction as much as we could. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Our hundred plus Stack Exchange sites and Teams instances share a lot of code, though the content and design may be different. Those differences are controlled by site settings, a smart configuration store that can scale to tens of thousands of sites without using up too much memory. To do that requires a database connection, so we needed to make some changes there as well. We had a settings mock set up for integrations tests, but it was horribly intercoupled. We set up an async context aware injection step before most of the other code hooks so independently running tests could initialize custom mock settings without using a database. As an additional benefit, this solved a bit of flakiness we saw from tests running in parallel, as they were no longer changing the same set of mock settings. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>We also want to be able to test our front-end code. For that, we implemented \u003Ca href=\"https://jestjs.io/\">Jest\u003C/a>, one of the most popular testing libraries in the JavaScript/TypeScript ecosystem. There are other solid testing libraries for JS/TS, most notably \u003Ca href=\"https://mochajs.org/\">Mocha\u003C/a>, but we’ve had good experiences using it in our Stacks editor, so we decided to bring it in for all of our front end-code. Jest is feature-rich—it’s fairly opinionated and batteries included, so we could get started with it quickly. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>At point, we can start writing tests. Based on these changes, we set up a testing cookbook in our Stack Overflow for Teams instance with details on how to write good unit and integration tests, mock data from databases, and cache testing data. As a proof of concept, we created our first real-world test using in-memory dependencies. Now we just have to write more tests. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2 id=\"h-good-tests-make-for-better-code\">Good tests make for better code\u003C/h2>\n\u003C!-- /wp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Writing a good unit test is not all that hard. Writing good, testable code is. The best ways to achieve testable code include writing pure functional code without dependencies. That’s not exactly possible in a modern web application. The second best way is to inject dependencies deliberately. In the past, we accessed a lot of objects from static contexts instead of passing them deliberately, which made it very difficult to create a testable version of that code. \u003C/p>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>With this, we’re committing to testability, to writing resilient code, and more importantly, moving quickly to implement new features that our customers and community want. We’re growing as well, which means our code quality becomes ever more important. Automated unit tests and testable code help in all these areas. \u003C/p>\n\u003C!-- /wp:paragraph -->","html","2022-07-04T14:00:00.000Z",{"current":476},"how-stack-overflow-is-leveling-up-its-unit-testing-game",[478,486,491,495],{"_createdAt":479,"_id":480,"_rev":481,"_type":482,"_updatedAt":479,"slug":483,"title":485},"2023-05-23T16:43:21Z","wp-tagcat-code-for-a-living","9HpbCsT2tq0xwozQfkc4ih","blogTag",{"current":484},"code-for-a-living","Code for a Living",{"_createdAt":479,"_id":487,"_rev":481,"_type":482,"_updatedAt":479,"slug":488,"title":490},"wp-tagcat-engineering",{"current":489},"engineering","Engineering",{"_createdAt":479,"_id":492,"_rev":481,"_type":482,"_updatedAt":479,"slug":493,"title":494},"wp-tagcat-testing",{"current":494},"testing",{"_createdAt":479,"_id":496,"_rev":481,"_type":482,"_updatedAt":479,"slug":497,"title":499},"wp-tagcat-unit-tests",{"current":498},"unit-tests","unit tests","How Stack Overflow is leveling up its unit testing game",[502,508,513,518],{"_id":503,"publishedAt":504,"slug":505,"sponsored":12,"title":507},"1d082483-6dc6-424b-8b09-9c84b54779da","2025-09-02T17:00:00.000Z",{"_type":10,"current":506},"back-to-school-developers-at-stack-overflow-have-some-advice-for-you","Back to school? Developers at Stack Overflow have some advice for you",{"_id":509,"publishedAt":504,"slug":510,"sponsored":12,"title":512},"5cd91820-9515-4be5-87ae-e919fd443c18",{"_type":10,"current":511},"getting-started-on-stack-overflow-a-step-by-step-guide-for-students","Getting started on Stack Overflow: a step-by-step guide for students",{"_id":514,"publishedAt":504,"slug":515,"sponsored":12,"title":517},"614538a9-c352-4024-adf1-fa44a9f911b6",{"_type":10,"current":516},"stack-overflow-is-helping-you-learn-to-code-with-new-resources","Stack Overflow is helping you learn to code with new resources",{"_id":519,"publishedAt":504,"slug":520,"sponsored":12,"title":522},"763b1d36-83d8-4178-9c2d-32d705ea1d7b",{"_type":10,"current":521},"introducing-your-newest-study-buddy-stackoverflow-ai","Introducing your newest study buddy: stackoverflow.ai",{"count":524,"lastTimestamp":525},13,"2023-05-25T09:47:53Z",["Reactive",527],{"$sarticleModal":528},false,["Set"],["ShallowReactive",531],{"sanity-NYUTaznhOjMvfTFI7X4Btcjx_YTEacjyeBxjJSEmdW4":-1,"sanity-comment-wp-post-20345-1756873110871":-1},"/2022/07/04/how-stack-overflow-is-leveling-up-its-unit-testing-game"]