[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"sanity-6UlwAs3ueJeC60t7biQY7z3yrKcRGcPbuTzxwKUH8xQ":3,"sanity-kkq-XjoMlTvg7uhTmfsdw6HaL8Oa1W20Ff09jP4-qjQ":1200},{"data":4,"sourceMap":-1},{"latestPodcast":5,"latestReleases":14,"post":39,"recent":1175},[6],{"_id":7,"publishedAt":8,"slug":9,"sponsored":12,"title":13},"5c7f0882-e1a7-4d0e-9e06-86cce9c3613a","2026-07-02T07:40:00.000Z",{"_type":10,"current":11},"slug","ai-coding-chaos-into-a-repeatable-playbook",null,"How do you turn AI coding chaos into a repeatable playbook?",[15,21,27,33],{"_id":16,"publishedAt":17,"slug":18,"title":20},"eb5b66eb-9410-4329-83bb-22bbff39402a","2026-04-28T13:00:00.000Z",{"_type":10,"current":19},"turn-scattered-knowledge-into-trusted-intelligence","Turning scattered knowledge into trusted intelligence: Stack Internal 2026.3",{"_id":22,"publishedAt":23,"slug":24,"title":26},"369c2401-b62e-4a37-8ff8-bf603023ecad","2026-03-02T15:03:00.988Z",{"_type":10,"current":25},"what-s-new-at-stack-overflow-march-2026","What’s new at Stack Overflow: March 2026",{"_id":28,"publishedAt":29,"slug":30,"title":32},"5e9053a4-07ea-447c-91ea-29e0b6228537","2026-02-02T15:00:00.000Z",{"_type":10,"current":31},"what-s-new-at-stack-overflow-february-2026","What’s new at Stack Overflow: February 2026",{"_id":34,"publishedAt":35,"slug":36,"title":38},"a1b538eb-a8a6-46d0-80a1-ac70ec9bb935","2026-01-05T10:00:00.000-05:00",{"_type":10,"current":37},"what-s-new-at-stack-overflow-january-2026","What’s new at Stack Overflow: January 2026",{"_createdAt":40,"_id":41,"_rev":42,"_type":43,"_updatedAt":44,"author":45,"body":62,"comments":1125,"dateUrl":1126,"excerpt":1127,"image":1128,"legacyBody":1131,"product":12,"publishedAt":1134,"slug":1135,"sponsored":12,"tags":1137,"title":1174,"visible":1125},"2023-05-24T12:50:58Z","wp-post-19326","LIB4H7UiOBRX1pcyrly96o","blogPost","2025-04-25T20:12:24Z",[46],{"_createdAt":47,"_id":48,"_rev":49,"_type":50,"_updatedAt":51,"avatar":52,"bio":57,"employee":58,"name":59,"slug":60},"2023-05-23T16:27:18Z","wp-author-cap-19328","dgl3SCUzppW3U2LvCoP6c0","blogAuthor","2023-06-20T15:05:12Z",{"_type":53,"asset":54},"image",{"_ref":55,"_type":56},"image-86a0c56b829a0bbe0f28e601dd213fe0e769b7b6-40x40-jpg","reference","","none","Mark Seeman",{"current":61},"mark-seeman",[63,108,116,120,150,158,167,191,195,203,218,226,234,260,268,276,284,292,300,326,360,368,387,402,405,469,488,491,530,538,548,556,564,583,609,632,640,670,703,706,735,767,782,790,798,806,833,836,876,879,894,897,927,930,967,993,1001,1024,1032,1049,1053,1061,1069,1077,1085,1093,1101,1109,1117],{"_key":64,"_type":65,"children":66,"markDefs":99,"style":107},"cd6e066f1253","block",[67,72,77,81,86,90,95],{"_key":68,"_type":69,"marks":70,"text":71},"cd6e066f12530","span",[],"If you’ve worked with ",{"_key":73,"_type":69,"marks":74,"text":76},"cd6e066f12531",[75],"1963b1aa66ef","unit testing",{"_key":78,"_type":69,"marks":79,"text":80},"cd6e066f12532",[],", you’ve probably used ",{"_key":82,"_type":69,"marks":83,"text":85},"cd6e066f12533",[84],"d1d828765bc4","dependency injection",{"_key":87,"_type":69,"marks":88,"text":89},"cd6e066f12534",[]," to be able to decouple objects and control their behavior while testing them. You’ve probably injected ",{"_key":91,"_type":69,"marks":92,"text":94},"cd6e066f12535",[93],"6e4964c945b8","mocks or stubs",{"_key":96,"_type":69,"marks":97,"text":98},"cd6e066f12536",[]," into the system under test in order to define repeatable, deterministic unit tests.",[100,103,105],{"_key":75,"_type":101,"href":102,"reference":12},"link","https:\u002F\u002Fstackoverflow.blog\u002F2017\u002F10\u002F17\u002Fpower-calculations-p-values-ab-testing-stack-overflow\u002F",{"_key":84,"_type":101,"href":104,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002Fdippp",{"_key":93,"_type":101,"href":106,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002F2013\u002F10\u002F23\u002Fmocks-for-commands-stubs-for-queries","normal",{"_key":109,"_type":65,"children":110,"markDefs":115,"style":107},"5200727c3de3",[111],{"_key":112,"_type":69,"marks":113,"text":114},"5200727c3de30",[],"Such a test might look like this:",[],{"_key":117,"_type":118,"code":119,"markDefs":12},"b0b09ab48cf2","code","[Fact]\npublic async Task AcceptWhenInnerManagerAccepts()\n{\n    var r = new Reservation(\n        DateTime.Now.AddDays(10).Date.AddHours(18),\n        \"x@example.com\",\n        \"\",\n        1);\n    var mgrTD = new Mock\u003CIReservationsManager>();\n    mgrTD.Setup(mgr => mgr.TrySave(r)).ReturnsAsync(true);\n    var sut = new RestaurantManager(\n        TimeSpan.FromHours(18),\n        TimeSpan.FromHours(21),\n        mgrTD.Object);\n \n    var actual = await sut.Check(r);\n \n    Assert.True(actual);\n}\n",{"_key":121,"_type":65,"children":122,"markDefs":145,"style":107},"5bd0ee081c0c",[123,127,132,136,141],{"_key":124,"_type":69,"marks":125,"text":126},"5bd0ee081c0c0",[],"(This C# test uses ",{"_key":128,"_type":69,"marks":129,"text":131},"5bd0ee081c0c1",[130],"c176469d541f","xUnit.net",{"_key":133,"_type":69,"marks":134,"text":135},"5bd0ee081c0c2",[]," 2.4.1 with ",{"_key":137,"_type":69,"marks":138,"text":140},"5bd0ee081c0c3",[139],"d72e73e95bea","Moq",{"_key":142,"_type":69,"marks":143,"text":144},"5bd0ee081c0c4",[]," 4.14.1.)",[146,148],{"_key":130,"_type":101,"href":147,"reference":12},"https:\u002F\u002Fxunit.net\u002F",{"_key":139,"_type":101,"href":149,"reference":12},"https:\u002F\u002Fgithub.com\u002Fmoq\u002Fmoq4",{"_key":151,"_type":65,"children":152,"markDefs":157,"style":107},"79f30a5c2548",[153],{"_key":154,"_type":69,"marks":155,"text":156},"79f30a5c25480",[],"Such tests are brittle. They break easily and therefore increase your maintenance burden.",[],{"_key":159,"_type":65,"children":160,"markDefs":165,"style":166},"b54b46500810",[161],{"_key":162,"_type":69,"marks":163,"text":164},"b54b465008100",[],"Why internal dependencies are bad",[],"h3",{"_key":168,"_type":65,"children":169,"markDefs":190,"style":107},"68bbf4b3c5c9",[170,174,178,182,186],{"_key":171,"_type":69,"marks":172,"text":173},"68bbf4b3c5c90",[],"As the above unit test implies, the ",{"_key":175,"_type":69,"marks":176,"text":177},"68bbf4b3c5c91",[118],"RestaurantManager",{"_key":179,"_type":69,"marks":180,"text":181},"68bbf4b3c5c92",[]," relies on an injected ",{"_key":183,"_type":69,"marks":184,"text":185},"68bbf4b3c5c93",[118],"IReservationsManager",{"_key":187,"_type":69,"marks":188,"text":189},"68bbf4b3c5c94",[]," dependency. This interface is an internal implementation detail. Think of the entire application as a blue box with two objects as internal components:",[],{"_key":192,"_type":53,"alt":12,"asset":193,"caption":57,"markDefs":12},"2eddff3219bd",{"_ref":194,"_type":56},"image-3de2273ade457ca704dec1aeb86eceacc4c918f6-275x324-png",{"_key":196,"_type":65,"children":197,"markDefs":202,"style":107},"a1a678802549",[198],{"_key":199,"_type":69,"marks":200,"text":201},"a1a6788025490",[],"An application contains many internal building blocks. The above illustration emphasizes two such components, and how they interact with each other.",[],{"_key":204,"_type":65,"children":205,"markDefs":217,"style":107},"c65c78d5d490",[206,210,213],{"_key":207,"_type":69,"marks":208,"text":209},"c65c78d5d4900",[],"What happens if you'd like to refactor the application code? Refactoring often involves changing how internal building blocks interact with each other. For example, you might want to change the ",{"_key":211,"_type":69,"marks":212,"text":185},"c65c78d5d4901",[118],{"_key":214,"_type":69,"marks":215,"text":216},"c65c78d5d4902",[]," interface.",[],{"_key":219,"_type":65,"children":220,"markDefs":225,"style":107},"923d670e0420",[221],{"_key":222,"_type":69,"marks":223,"text":224},"923d670e04200",[],"When you make a change like that, you'll break some of the code that relies on the interface. That's to be expected. Refactoring, after all, involves changing code.",[],{"_key":227,"_type":65,"children":228,"markDefs":233,"style":107},"0d42f486e88d",[229],{"_key":230,"_type":69,"marks":231,"text":232},"0d42f486e88d0",[],"When your tests also rely on internal implementation details, refactoring also breaks the tests. Now, in addition to improving the internal code, you also have to fix all the tests that broke.",[],{"_key":235,"_type":65,"children":236,"markDefs":258,"style":107},"c136f346eec0",[237,241,246,250,254],{"_key":238,"_type":69,"marks":239,"text":240},"c136f346eec00",[],"Using a ",{"_key":242,"_type":69,"marks":243,"text":245},"c136f346eec01",[244],"em","dynamic mock library",{"_key":247,"_type":69,"marks":248,"text":249},"c136f346eec02",[]," like ",{"_key":251,"_type":69,"marks":252,"text":140},"c136f346eec03",[253],"97dd65cde70a",{"_key":255,"_type":69,"marks":256,"text":257},"c136f346eec04",[]," tends to amplify the problem. You now have to visit all the tests that configure mocks and adjust them to model the new internal interaction.",[259],{"_key":253,"_type":101,"href":149,"reference":12},{"_key":261,"_type":65,"children":262,"markDefs":267,"style":107},"d6f133fd16ad",[263],{"_key":264,"_type":69,"marks":265,"text":266},"d6f133fd16ad0",[],"This kind of friction is likely to deter you from refactoring in the first place. If you know that a warranted refactoring will give you much extra work fixing tests, you may decide that it isn't worth the trouble. Instead, you leave the production code in a suboptimal state.",[],{"_key":269,"_type":65,"children":270,"markDefs":275,"style":107},"f86dad6961b2",[271],{"_key":272,"_type":69,"marks":273,"text":274},"f86dad6961b20",[],"Is there a better way?",[],{"_key":277,"_type":65,"children":278,"markDefs":283,"style":166},"4c092bfc620c",[279],{"_key":280,"_type":69,"marks":281,"text":282},"4c092bfc620c0",[],"Functional core",[],{"_key":285,"_type":65,"children":286,"markDefs":291,"style":107},"6385cd48a95a",[287],{"_key":288,"_type":69,"marks":289,"text":290},"6385cd48a95a0",[],"In order to find a better alternative, you must first understand the problem. Why use test doubles (mocks and stubs) in the first place?",[],{"_key":293,"_type":65,"children":294,"markDefs":299,"style":107},"1e6b3cd249a6",[295],{"_key":296,"_type":69,"marks":297,"text":298},"1e6b3cd249a60",[],"Test doubles serve a major purpose: They enable us to write deterministic unit tests.",[],{"_key":301,"_type":65,"children":302,"markDefs":321,"style":107},"6b714beff317",[303,308,312,317],{"_key":304,"_type":69,"marks":305,"text":307},"6b714beff3170",[306],"04b349e037fe","Unit tests should be deterministic",{"_key":309,"_type":69,"marks":310,"text":311},"6b714beff3171",[],". Running a test multiple times should produce the same outcome each time (",{"_key":313,"_type":69,"marks":314,"text":316},"6b714beff3172",[315],"2dcdf4d0aacd","ceteris paribus",{"_key":318,"_type":69,"marks":319,"text":320},"6b714beff3173",[],"). A test that succeeds on a Wednesday shouldn't fail on a Saturday.",[322,324],{"_key":306,"_type":101,"href":323,"reference":12},"https:\u002F\u002Fmartinfowler.com\u002Farticles\u002FnonDeterminism.html",{"_key":315,"_type":101,"href":325,"reference":12},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCeteris_paribus",{"_key":327,"_type":65,"children":328,"markDefs":355,"style":107},"ca2e6f3206f1",[329,333,338,342,346,351],{"_key":330,"_type":69,"marks":331,"text":332},"ca2e6f3206f10",[],"By using a test double each test can control how a dependency behaves. In ",{"_key":334,"_type":69,"marks":335,"text":337},"ca2e6f3206f11",[336,244],"80aaf969bf48","Working Effectively with Legacy Code",{"_key":339,"_type":69,"marks":340,"text":341},"ca2e6f3206f12",[244],",",{"_key":343,"_type":69,"marks":344,"text":345},"ca2e6f3206f13",[]," Michael Feathers likens a test to a ",{"_key":347,"_type":69,"marks":348,"text":350},"ca2e6f3206f14",[349],"e3425a894c1c","vise",{"_key":352,"_type":69,"marks":353,"text":354},"ca2e6f3206f15",[],". It's a tool to fix a particular behavior in place.",[356,358],{"_key":336,"_type":101,"href":357,"reference":12},"http:\u002F\u002Fbit.ly\u002Fworking-effectively-with-legacy-code",{"_key":349,"_type":101,"href":359,"reference":12},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVise",{"_key":361,"_type":65,"children":362,"markDefs":367,"style":107},"6fc9f2d8f889",[363],{"_key":364,"_type":69,"marks":365,"text":366},"6fc9f2d8f8890",[],"Test doubles, however, aren't the only way to make tests deterministic.",[],{"_key":369,"_type":65,"children":370,"markDefs":384,"style":107},"fa13d7e56b93",[371,375,380],{"_key":372,"_type":69,"marks":373,"text":374},"fa13d7e56b930",[],"A better alternative is to make the production code itself deterministic. Imagine, for example, that you need to write code that calculates the volume of a ",{"_key":376,"_type":69,"marks":377,"text":379},"fa13d7e56b931",[378],"569618651b90","frustum",{"_key":381,"_type":69,"marks":382,"text":383},"fa13d7e56b932",[],". As long as the frustum doesn't change, the volume remains the same number. Such a calculation is entirely deterministic.",[385],{"_key":378,"_type":101,"href":386,"reference":12},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFrustum",{"_key":388,"_type":65,"children":389,"markDefs":401,"style":107},"110dee9afb0a",[390,394,397],{"_key":391,"_type":69,"marks":392,"text":393},"110dee9afb0a0",[],"Write your production code using mostly deterministic operations. For example, instead of the above ",{"_key":395,"_type":69,"marks":396,"text":177},"110dee9afb0a1",[118],{"_key":398,"_type":69,"marks":399,"text":400},"110dee9afb0a2",[],", you can write an immutable class with a method like this:",[],{"_key":403,"_type":118,"code":404,"markDefs":12},"3b9a1fe2256c","public bool WillAccept(\n    DateTime now,\n    IEnumerable\u003CReservation> existingReservations,\n    Reservation candidate)\n{\n    if (existingReservations is null)\n        throw new ArgumentNullException(nameof(existingReservations));\n    if (candidate is null)\n        throw new ArgumentNullException(nameof(candidate));\n    if (candidate.At \u003C now)\n        return false;\n    if (IsOutsideOfOpeningHours(candidate))\n        return false;\n \n    var seating = new Seating(SeatingDuration, candidate.At);\n    var relevantReservations =\n        existingReservations.Where(seating.Overlaps);\n    var availableTables = Allocate(relevantReservations);\n    return availableTables.Any(t => t.Fits(candidate.Quantity));\n}\n",{"_key":406,"_type":65,"children":407,"markDefs":462,"style":107},"71b070911c0f",[408,412,417,421,426,430,435,439,443,447,451,454,458],{"_key":409,"_type":69,"marks":410,"text":411},"71b070911c0f0",[],"This example, like all code in this article, is from my book ",{"_key":413,"_type":69,"marks":414,"text":416},"71b070911c0f1",[415,244],"60914d1eabdf","Code That Fits in Your Head",{"_key":418,"_type":69,"marks":419,"text":420},"71b070911c0f2",[],". Despite implementing ",{"_key":422,"_type":69,"marks":423,"text":425},"71b070911c0f3",[424],"6223b322b39e","quite complex business logic",{"_key":427,"_type":69,"marks":428,"text":429},"71b070911c0f4",[],", it's a ",{"_key":431,"_type":69,"marks":432,"text":434},"71b070911c0f5",[433],"b5e1f430eceb","pure function",{"_key":436,"_type":69,"marks":437,"text":438},"71b070911c0f6",[],". All the helper methods involved (",{"_key":440,"_type":69,"marks":441,"text":442},"71b070911c0f7",[118],"IsOutsideOfOpeningHours",{"_key":444,"_type":69,"marks":445,"text":446},"71b070911c0f8",[],", ",{"_key":448,"_type":69,"marks":449,"text":450},"71b070911c0f9",[118],"Overlaps",{"_key":452,"_type":69,"marks":453,"text":446},"71b070911c0f10",[],{"_key":455,"_type":69,"marks":456,"text":457},"71b070911c0f11",[118],"Allocate",{"_key":459,"_type":69,"marks":460,"text":461},"71b070911c0f12",[],", etc.) are also deterministic.",[463,465,467],{"_key":415,"_type":101,"href":464,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002Fcode-that-fits-in-your-head",{"_key":424,"_type":101,"href":466,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002F2020\u002F01\u002F27\u002Fthe-maitre-d-kata",{"_key":433,"_type":101,"href":468,"reference":12},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPure_function",{"_key":470,"_type":65,"children":471,"markDefs":485,"style":107},"3b760b90b6b9",[472,476,481],{"_key":473,"_type":69,"marks":474,"text":475},"3b760b90b6b90",[],"The upshot is that ",{"_key":477,"_type":69,"marks":478,"text":480},"3b760b90b6b91",[479],"76a892e3cba7","deterministic operations are easy to test",{"_key":482,"_type":69,"marks":483,"text":484},"3b760b90b6b92",[],". For instance, here's a parametrized test of the happy path:",[486],{"_key":479,"_type":101,"href":487,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002F2015\u002F05\u002F07\u002Ffunctional-design-is-intrinsically-testable",{"_key":489,"_type":118,"code":490,"markDefs":12},"adf99869033c","[Theory, ClassData(typeof(AcceptTestCases))]\npublic void Accept(MaitreD sut, DateTime now, IEnumerable\u003CReservation> reservations)\n{\n    var r = Some.Reservation.WithQuantity(11);\n    var actual = sut.WillAccept(now, reservations, r);\n    Assert.True(actual);\n}\n",{"_key":492,"_type":65,"children":493,"markDefs":529,"style":107},"128ce1720e31",[494,498,502,506,510,513,517,521,525],{"_key":495,"_type":69,"marks":496,"text":497},"128ce1720e310",[],"This code snippet doesn't show the test case data source (",{"_key":499,"_type":69,"marks":500,"text":501},"128ce1720e311",[118],"AcceptTestCases",{"_key":503,"_type":69,"marks":504,"text":505},"128ce1720e312",[],"), but it's a small helper class that produces seven test cases that supply values for ",{"_key":507,"_type":69,"marks":508,"text":509},"128ce1720e313",[118],"sut",{"_key":511,"_type":69,"marks":512,"text":446},"128ce1720e314",[],{"_key":514,"_type":69,"marks":515,"text":516},"128ce1720e315",[118],"now",{"_key":518,"_type":69,"marks":519,"text":520},"128ce1720e316",[],", and ",{"_key":522,"_type":69,"marks":523,"text":524},"128ce1720e317",[118],"reservations",{"_key":526,"_type":69,"marks":527,"text":528},"128ce1720e318",[],".",[],{"_key":531,"_type":65,"children":532,"markDefs":537,"style":107},"ab5b619b1af0",[533],{"_key":534,"_type":69,"marks":535,"text":536},"ab5b619b1af00",[],"This test method is typical of unit tests of pure functions:",[],{"_key":539,"_type":65,"children":540,"level":545,"listItem":546,"markDefs":547,"style":107},"4895d661069b",[541],{"_key":542,"_type":69,"marks":543,"text":544},"4895d661069b0",[],"Prepare input value(s)",1,"number",[],{"_key":549,"_type":65,"children":550,"level":545,"listItem":546,"markDefs":555,"style":107},"e58da0457ee5",[551],{"_key":552,"_type":69,"marks":553,"text":554},"e58da0457ee50",[],"Call the function",[],{"_key":557,"_type":65,"children":558,"level":545,"listItem":546,"markDefs":563,"style":107},"071de62272a4",[559],{"_key":560,"_type":69,"marks":561,"text":562},"071de62272a40",[],"Compare the expected outcome with the actual value",[],{"_key":565,"_type":65,"children":566,"markDefs":580,"style":107},"72c7f9b84810",[567,571,576],{"_key":568,"_type":69,"marks":569,"text":570},"72c7f9b848100",[],"If you recognize ",{"_key":572,"_type":69,"marks":573,"text":575},"72c7f9b848101",[574],"ae82ae94c48f","that structure as the Arrange Act Assert pattern",{"_key":577,"_type":69,"marks":578,"text":579},"72c7f9b848102",[],", you're not wrong, but that's not the main point. What's worth noticing is that despite non-trivial business logic, no test doubles (i.e. mocks or stubs) are required. This is one of many advantages of pure functions. Since they are already deterministic, you don't have to introduce artificial seams into the code to enable testing.",[581],{"_key":574,"_type":101,"href":582,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002F2013\u002F06\u002F24\u002Fa-heuristic-for-formatting-code-according-to-the-aaa-pattern",{"_key":584,"_type":65,"children":585,"markDefs":606,"style":107},"b8f8d812b57e",[586,590,594,598,603],{"_key":587,"_type":69,"marks":588,"text":589},"b8f8d812b57e0",[],"Writing most of a code base as deterministic functions is possible, but requires practice. This style of programming is called ",{"_key":591,"_type":69,"marks":592,"text":593},"b8f8d812b57e1",[244],"functional programming",{"_key":595,"_type":69,"marks":596,"text":597},"b8f8d812b57e2",[]," (FP), and while it may require effort for object-oriented programmers to shift perspective, it's quite the game changer—both because of the benefits to testing, and for ",{"_key":599,"_type":69,"marks":600,"text":602},"b8f8d812b57e3",[601],"e174c1c7a1ec","other reasons",{"_key":604,"_type":69,"marks":605,"text":528},"b8f8d812b57e4",[],[607],{"_key":601,"_type":101,"href":608,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002F2021\u002F07\u002F28\u002Freferential-transparency-fits-in-your-head",{"_key":610,"_type":65,"children":611,"markDefs":631,"style":107},"1ad0246148e8",[612,616,619,623,627],{"_key":613,"_type":69,"marks":614,"text":615},"1ad0246148e80",[],"Even the most idiomatic FP code base, however, must deal with the messy, non-deterministic real world. Where do input values like ",{"_key":617,"_type":69,"marks":618,"text":516},"1ad0246148e81",[118],{"_key":620,"_type":69,"marks":621,"text":622},"1ad0246148e82",[]," and ",{"_key":624,"_type":69,"marks":625,"text":626},"1ad0246148e83",[118],"existingReservations",{"_key":628,"_type":69,"marks":629,"text":630},"1ad0246148e84",[]," come from?",[],{"_key":633,"_type":65,"children":634,"markDefs":639,"style":166},"3667a9a37f10",[635],{"_key":636,"_type":69,"marks":637,"text":638},"3667a9a37f100",[],"Imperative shell",[],{"_key":641,"_type":65,"children":642,"markDefs":665,"style":107},"02d0c43553f5",[643,647,652,656,661],{"_key":644,"_type":69,"marks":645,"text":646},"02d0c43553f50",[],"A typical ",{"_key":648,"_type":69,"marks":649,"text":651},"02d0c43553f51",[650],"606f684aee06","functional architecture",{"_key":653,"_type":69,"marks":654,"text":655},"02d0c43553f52",[]," tends to ",{"_key":657,"_type":69,"marks":658,"text":660},"02d0c43553f53",[659],"e9c68f53b2d2","resemble the Ports and Adapters architecture",{"_key":662,"_type":69,"marks":663,"text":664},"02d0c43553f54",[],". You implement all business and application logic as pure functions and push impure actions to the edge.",[666,668],{"_key":650,"_type":101,"href":667,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002F2018\u002F11\u002F19\u002Ffunctional-architecture-a-definition",{"_key":659,"_type":101,"href":669,"reference":12},"https:\u002F\u002Fblog.ploeh.dk\u002F2016\u002F03\u002F18\u002Ffunctional-architecture-is-ports-and-adapters",{"_key":671,"_type":65,"children":672,"markDefs":701,"style":107},"18026ef01537",[673,677,681,685,689,693,697],{"_key":674,"_type":69,"marks":675,"text":676},"18026ef015370",[],"At the edge, and only at the edge, you allow impure actions to take place. In the example code that runs through ",{"_key":678,"_type":69,"marks":679,"text":416},"18026ef015371",[680,244],"180ce76fddb7",{"_key":682,"_type":69,"marks":683,"text":684},"18026ef015372",[],", this happens in controllers. For example, this ",{"_key":686,"_type":69,"marks":687,"text":688},"18026ef015373",[118],"TryCreate",{"_key":690,"_type":69,"marks":691,"text":692},"18026ef015374",[]," helper method is defined in a ",{"_key":694,"_type":69,"marks":695,"text":696},"18026ef015375",[118],"ReservationsController",{"_key":698,"_type":69,"marks":699,"text":700},"18026ef015376",[]," class:",[702],{"_key":680,"_type":101,"href":464,"reference":12},{"_key":704,"_type":118,"code":705,"markDefs":12},"c05e12e4f001","private async Task\u003CActionResult> TryCreate(\n    Restaurant restaurant,\n    Reservation reservation)\n{\n    using var scope =\n        new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);\n \n    var reservations = await Repository\n        .ReadReservations(restaurant.Id, reservation.At)\n        .ConfigureAwait(false);\n    var now = Clock.GetCurrentDateTime();\n    if (!restaurant.MaitreD.WillAccept(now, reservations, reservation))\n        return NoTables500InternalServerError();\n \n    await Repository.Create(restaurant.Id, reservation)\n        .ConfigureAwait(false);\n \n    scope.Complete();\n \n    return Reservation201Created(restaurant.Id, reservation);\n}\n",{"_key":707,"_type":65,"children":708,"markDefs":734,"style":107},"dc5b030aa5c4",[709,713,716,720,724,727,731],{"_key":710,"_type":69,"marks":711,"text":712},"dc5b030aa5c40",[],"The ",{"_key":714,"_type":69,"marks":715,"text":688},"dc5b030aa5c41",[118],{"_key":717,"_type":69,"marks":718,"text":719},"dc5b030aa5c42",[]," method makes use of two impure, injected dependencies: ",{"_key":721,"_type":69,"marks":722,"text":723},"dc5b030aa5c43",[118],"Repository",{"_key":725,"_type":69,"marks":726,"text":622},"dc5b030aa5c44",[],{"_key":728,"_type":69,"marks":729,"text":730},"dc5b030aa5c45",[118],"Clock",{"_key":732,"_type":69,"marks":733,"text":528},"dc5b030aa5c46",[],[],{"_key":736,"_type":65,"children":737,"markDefs":764,"style":107},"6bb6f9b9683e",[738,741,744,748,751,755,760],{"_key":739,"_type":69,"marks":740,"text":712},"6bb6f9b9683e0",[],{"_key":742,"_type":69,"marks":743,"text":723},"6bb6f9b9683e1",[118],{"_key":745,"_type":69,"marks":746,"text":747},"6bb6f9b9683e2",[]," dependency represents the database that stores reservations, while ",{"_key":749,"_type":69,"marks":750,"text":730},"6bb6f9b9683e3",[118],{"_key":752,"_type":69,"marks":753,"text":754},"6bb6f9b9683e4",[]," represents some kind of clock. These dependencies aren't arbitrary. They're there to support unit testing of the application's ",{"_key":756,"_type":69,"marks":757,"text":759},"6bb6f9b9683e5",[758,244],"d5ba0e8ee684","imperative shell",{"_key":761,"_type":69,"marks":762,"text":763},"6bb6f9b9683e6",[],", and they have to be injected dependencies exactly because they're sources of non-determinism.",[765],{"_key":758,"_type":101,"href":766,"reference":12},"https:\u002F\u002Fwww.kennethlange.com\u002Ffunctional-core-imperative-shell\u002F",{"_key":768,"_type":65,"children":769,"markDefs":781,"style":107},"247a187c224c",[770,774,777],{"_key":771,"_type":69,"marks":772,"text":773},"247a187c224c0",[],"It's easiest to understand why ",{"_key":775,"_type":69,"marks":776,"text":730},"247a187c224c1",[118],{"_key":778,"_type":69,"marks":779,"text":780},"247a187c224c2",[]," is a source of non-determinism. Every time you ask what time it is, the answer changes. That's non-deterministic, because the textbook definition of determinism is that the same input should always produce the same output.",[],{"_key":783,"_type":65,"children":784,"markDefs":789,"style":107},"f25b5393bb7e",[785],{"_key":786,"_type":69,"marks":787,"text":788},"f25b5393bb7e0",[],"The same definition applies to databases. You can repeat the same database query, and over time receive different outputs because the state of the database changes. By the definition of determinism, that makes a database non-deterministic: The same input may produce varying outputs.",[],{"_key":791,"_type":65,"children":792,"markDefs":797,"style":107},"778ce2a18a43",[793],{"_key":794,"_type":69,"marks":795,"text":796},"778ce2a18a430",[],"You can still unit test the imperative shell, but you don't have to use brittle dynamic mock objects. Instead, use Fakes.",[],{"_key":799,"_type":65,"children":800,"markDefs":805,"style":166},"e5e34355c936",[801],{"_key":802,"_type":69,"marks":803,"text":804},"e5e34355c9360",[],"Fakes",[],{"_key":807,"_type":65,"children":808,"markDefs":830,"style":107},"5d673c12e5f0",[809,813,818,822,826],{"_key":810,"_type":69,"marks":811,"text":812},"5d673c12e5f00",[],"In the pattern language of ",{"_key":814,"_type":69,"marks":815,"text":817},"5d673c12e5f01",[816],"6c4798f933fa","xUnit Test Patterns",{"_key":819,"_type":69,"marks":820,"text":821},"5d673c12e5f02",[],", a fake is a kind of test double that could ",{"_key":823,"_type":69,"marks":824,"text":825},"5d673c12e5f03",[244],"almost",{"_key":827,"_type":69,"marks":828,"text":829},"5d673c12e5f04",[]," serve as a “real” implementation of an interface. An in-memory “database” is a useful example:",[831],{"_key":816,"_type":101,"href":832,"reference":12},"http:\u002F\u002Fbit.ly\u002Fxunitpatterns",{"_key":834,"_type":118,"code":835,"markDefs":12},"1a98d3b213eb","public sealed class FakeDatabase :\n    ConcurrentDictionary\u003Cint, Collection\u003CReservation>>,\n    IReservationsRepository\n",{"_key":837,"_type":65,"children":838,"markDefs":875,"style":107},"e2de80ef3a51",[839,843,847,851,855,859,863,867,871],{"_key":840,"_type":69,"marks":841,"text":842},"e2de80ef3a510",[],"While implementing ",{"_key":844,"_type":69,"marks":845,"text":846},"e2de80ef3a511",[118],"IReservationsRepository",{"_key":848,"_type":69,"marks":849,"text":850},"e2de80ef3a512",[],", this test-specific ",{"_key":852,"_type":69,"marks":853,"text":854},"e2de80ef3a513",[118],"FakeDatabase",{"_key":856,"_type":69,"marks":857,"text":858},"e2de80ef3a514",[]," class inherits ",{"_key":860,"_type":69,"marks":861,"text":862},"e2de80ef3a515",[118],"ConcurrentDictionary\u003Cint, Collection\u003CReservation>>",{"_key":864,"_type":69,"marks":865,"text":866},"e2de80ef3a516",[],", which means it can leverage the dictionary base class to add and remove reservations. Here's the ",{"_key":868,"_type":69,"marks":869,"text":870},"e2de80ef3a517",[118],"Create",{"_key":872,"_type":69,"marks":873,"text":874},"e2de80ef3a518",[]," implementation:",[],{"_key":877,"_type":118,"code":878,"markDefs":12},"7a5fd1366868","public Task Create(int restaurantId, Reservation reservation)\n{\n    AddOrUpdate(\n        restaurantId,\n        new Collection\u003CReservation> { reservation },\n        (_, rs) => { rs.Add(reservation); return rs; });\n    return Task.CompletedTask;\n}\n",{"_key":880,"_type":65,"children":881,"markDefs":893,"style":107},"9053c19f3ffd",[882,886,890],{"_key":883,"_type":69,"marks":884,"text":885},"9053c19f3ffd0",[],"And here's the ",{"_key":887,"_type":69,"marks":888,"text":889},"9053c19f3ffd1",[118],"ReadReservations",{"_key":891,"_type":69,"marks":892,"text":874},"9053c19f3ffd2",[],[],{"_key":895,"_type":118,"code":896,"markDefs":12},"eb256bf2b820","public Task\u003CIReadOnlyCollection\u003CReservation>> ReadReservations(\n    int restaurantId,\n    DateTime min,\n    DateTime max)\n{\n    return Task.FromResult\u003CIReadOnlyCollection\u003CReservation>>(\n        GetOrAdd(restaurantId, new Collection\u003CReservation>())\n            .Where(r => min \u003C= r.At && r.At \u003C= max).ToList());\n}\n",{"_key":898,"_type":65,"children":899,"markDefs":926,"style":107},"52d3f5d222ae",[900,903,906,910,914,918,922],{"_key":901,"_type":69,"marks":902,"text":712},"52d3f5d222ae0",[],{"_key":904,"_type":69,"marks":905,"text":889},"52d3f5d222ae1",[118],{"_key":907,"_type":69,"marks":908,"text":909},"52d3f5d222ae2",[]," will return the reservations already added to the repository with the ",{"_key":911,"_type":69,"marks":912,"text":913},"52d3f5d222ae3",[118],"Create ",{"_key":915,"_type":69,"marks":916,"text":917},"52d3f5d222ae4",[],"method. Of course, it only works as long as the ",{"_key":919,"_type":69,"marks":920,"text":921},"52d3f5d222ae5",[118],"FakeDatabase ",{"_key":923,"_type":69,"marks":924,"text":925},"52d3f5d222ae6",[],"object remains in memory, but that's sufficient for a unit test:",[],{"_key":928,"_type":118,"code":929,"markDefs":12},"d78055df79ef","[Theory]\n[InlineData(1049, 19, 00, \"juliad@example.net\", \"Julia Domna\", 5)]\n[InlineData(1130, 18, 15, \"x@example.com\", \"Xenia Ng\", 9)]\n[InlineData( 956, 16, 55, \"kite@example.edu\", null, 2)]\n[InlineData( 433, 17, 30, \"shli@example.org\", \"Shanghai Li\", 5)]\npublic async Task PostValidReservationWhenDatabaseIsEmpty(\n    int days,\n    int hours,\n    int minutes,\n    string email,\n    string name,\n    int quantity)\n{\n    var at = DateTime.Now.Date + new TimeSpan(days, hours, minutes, 0);\n    var db = new FakeDatabase();\n    var sut = new ReservationsController(\n        new SystemClock(),\n        new InMemoryRestaurantDatabase(Grandfather.Restaurant),\n        db);\n \n    var dto = new ReservationDto\n    {\n        Id = \"B50DF5B1-F484-4D99-88F9-1915087AF568\",\n        At = at.ToString(\"O\"),\n        Email = email,\n        Name = name,\n        Quantity = quantity\n    };\n    await sut.Post(dto);\n \n    var expected = new Reservation(\n        Guid.Parse(dto.Id),\n        at,\n        new Email(email),\n        new Name(name ?? \"\"),\n        quantity);\n    Assert.Contains(expected, db.Grandfather);\n}\n",{"_key":931,"_type":65,"children":932,"markDefs":966,"style":107},"d3bd3190fbcd",[933,937,940,944,948,952,955,959,962],{"_key":934,"_type":69,"marks":935,"text":936},"d3bd3190fbcd0",[],"This test injects a ",{"_key":938,"_type":69,"marks":939,"text":854},"d3bd3190fbcd1",[118],{"_key":941,"_type":69,"marks":942,"text":943},"d3bd3190fbcd2",[]," variable called ",{"_key":945,"_type":69,"marks":946,"text":947},"d3bd3190fbcd3",[118],"db",{"_key":949,"_type":69,"marks":950,"text":951},"d3bd3190fbcd4",[]," and ultimately asserts that ",{"_key":953,"_type":69,"marks":954,"text":947},"d3bd3190fbcd5",[118],{"_key":956,"_type":69,"marks":957,"text":958},"d3bd3190fbcd6",[]," has the expected state. Since ",{"_key":960,"_type":69,"marks":961,"text":947},"d3bd3190fbcd7",[118],{"_key":963,"_type":69,"marks":964,"text":965},"d3bd3190fbcd8",[]," stays in scope for the duration of the test, its behavior is deterministic and consistent.",[],{"_key":968,"_type":65,"children":969,"markDefs":990,"style":107},"76399a8bc59d",[970,974,977,981,986],{"_key":971,"_type":69,"marks":972,"text":973},"76399a8bc59d0",[],"Using a fake is more robust in the face of change. If you wish to refactor code that involves changes to an interface like ",{"_key":975,"_type":69,"marks":976,"text":846},"76399a8bc59d1",[118],{"_key":978,"_type":69,"marks":979,"text":980},"76399a8bc59d2",[],", the only change you'll need to make to the test code is to edit the fake implementation to make sure that it still preserves the invariants of the type. That's one test file you'll have to maintain, rather than the ",{"_key":982,"_type":69,"marks":983,"text":985},"76399a8bc59d3",[984],"1069da60c452","shotgun surgery",{"_key":987,"_type":69,"marks":988,"text":989},"76399a8bc59d4",[]," necessary when using dynamic mock libraries.",[991],{"_key":984,"_type":101,"href":992,"reference":12},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FShotgun_surgery",{"_key":994,"_type":65,"children":995,"markDefs":1000,"style":166},"d73e481de5f8",[996],{"_key":997,"_type":69,"marks":998,"text":999},"d73e481de5f80",[],"Architectural dependencies",[],{"_key":1002,"_type":65,"children":1003,"markDefs":1023,"style":107},"3926be328908",[1004,1008,1012,1016,1019],{"_key":1005,"_type":69,"marks":1006,"text":1007},"3926be3289080",[],"To recap: A ",{"_key":1009,"_type":69,"marks":1010,"text":1011},"3926be3289081",[244],"functional core",{"_key":1013,"_type":69,"marks":1014,"text":1015},"3926be3289082",[]," needs no dependency injection to support unit testing, because functions are always testable (being deterministic by definition). Only the ",{"_key":1017,"_type":69,"marks":1018,"text":759},"3926be3289083",[244],{"_key":1020,"_type":69,"marks":1021,"text":1022},"3926be3289084",[]," needs dependency injection to support unit testing.",[],{"_key":1025,"_type":65,"children":1026,"markDefs":1031,"style":107},"36b5e68bdc7c",[1027],{"_key":1028,"_type":69,"marks":1029,"text":1030},"36b5e68bdc7c0",[],"Which dependencies are required? Every source of non-deterministic behavior and side effects. This tends to correspond to the actual, architectural dependencies of the application in question, with the possible addition of a clock and a random number generator.",[],{"_key":1033,"_type":65,"children":1034,"markDefs":1047,"style":107},"cf2325b6b401",[1035,1039,1043],{"_key":1036,"_type":69,"marks":1037,"text":1038},"cf2325b6b4010",[],"The sample system in ",{"_key":1040,"_type":69,"marks":1041,"text":416},"cf2325b6b4011",[1042,244],"540046762d25",{"_key":1044,"_type":69,"marks":1045,"text":1046},"cf2325b6b4012",[]," has three “real” dependencies: Its database, an SMTP gateway, and the system clock:",[1048],{"_key":1042,"_type":101,"href":464,"reference":12},{"_key":1050,"_type":53,"alt":12,"asset":1051,"caption":57,"markDefs":12},"55c4ef3ee53e",{"_ref":1052,"_type":56},"image-73ed9dc1607d90c4e143cf208e5caa3634c5358b-275x465-png",{"_key":1054,"_type":65,"children":1055,"markDefs":1060,"style":107},"e3ced8b2fd69",[1056],{"_key":1057,"_type":69,"marks":1058,"text":1059},"e3ced8b2fd690",[],"Apart from the system clock, these dependencies are components you'd also draw when illustrating the overall architecture of the system. The application is an opaque box, its internal organization implementation details, but its “real” dependencies represent other processes that may run somewhere else on the network.",[],{"_key":1062,"_type":65,"children":1063,"markDefs":1068,"style":107},"23ea7254f167",[1064],{"_key":1065,"_type":69,"marks":1066,"text":1067},"23ea7254f1670",[],"These dependencies are the ones you may consider to explicitly model. These dependencies you can hide behind interfaces, inject with Constructor Injection, and replace using test doubles. Not mocks, stubs, or spies, but fakes.",[],{"_key":1070,"_type":65,"children":1071,"markDefs":1076,"style":166},"244c533cdd6a",[1072],{"_key":1073,"_type":69,"marks":1074,"text":1075},"244c533cdd6a0",[],"Conclusion",[],{"_key":1078,"_type":65,"children":1079,"markDefs":1084,"style":107},"a94ef0d4420c",[1080],{"_key":1081,"_type":69,"marks":1082,"text":1083},"a94ef0d4420c0",[],"Which dependencies should be present in your code base?",[],{"_key":1086,"_type":65,"children":1087,"markDefs":1092,"style":107},"8d2a8aa86dba",[1088],{"_key":1089,"_type":69,"marks":1090,"text":1091},"8d2a8aa86dba0",[],"Those that represent non-deterministic behavior or side effects. Adding rows to a database. Sending an email. Getting the current time and date. Querying a database.",[],{"_key":1094,"_type":65,"children":1095,"markDefs":1100,"style":107},"b6f941597886",[1096],{"_key":1097,"_type":69,"marks":1098,"text":1099},"b6f9415978860",[],"These tend to correspond to the architectural dependencies of the system in question. If the application requires a database in order to work correctly, you'll model the database as a polymorphic dependency. If the system must be able to send email, then a messaging gateway interface is warranted.",[],{"_key":1102,"_type":65,"children":1103,"markDefs":1108,"style":107},"f2163f1140c9",[1104],{"_key":1105,"_type":69,"marks":1106,"text":1107},"f2163f1140c90",[],"In addition to such architectural dependencies, system time and random number generators are the other well-known sources of non-determinism, so model those as explicit dependencies as well.",[],{"_key":1110,"_type":65,"children":1111,"markDefs":1116,"style":107},"7183d7dedf1b",[1112],{"_key":1113,"_type":69,"marks":1114,"text":1115},"7183d7dedf1b0",[],"That's it. Those are the dependencies you need. The rest are implementation details, likely to make your test code more brittle.",[],{"_key":1118,"_type":65,"children":1119,"markDefs":1124,"style":107},"67b05a98a483",[1120],{"_key":1121,"_type":69,"marks":1122,"text":1123},"67b05a98a4830",[],"The implication is that a typical system will only have a handful of dependencies.",[],true,"2022\u002F01\u002F03","Which dependencies should be present in your code base? This article suggests an answer to that question.",{"_type":53,"asset":1129},{"_ref":1130,"_type":56},"image-a787256fba2cd1e1505a4a4f39eccfbe89740909-2400x1260-jpg",{"code":1132,"language":1133},"\u003C!-- wp:paragraph -->\n\u003Cp>If you’ve worked with \u003Ca href=\"https:\u002F\u002Fstackoverflow.blog\u002F2017\u002F10\u002F17\u002Fpower-calculations-p-values-ab-testing-stack-overflow\u002F\">unit testing\u003C\u002Fa>, you’ve probably used \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002Fdippp\">dependency injection\u003C\u002Fa> to be able to decouple objects and control their behavior while testing them. You’ve probably injected \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002F2013\u002F10\u002F23\u002Fmocks-for-commands-stubs-for-queries\">mocks or stubs\u003C\u002Fa> into the system under test in order to define repeatable, deterministic unit tests.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Such a test might look like this:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&#91;Fact]\npublic async Task AcceptWhenInnerManagerAccepts()\n{\n    var r = new Reservation(\n        DateTime.Now.AddDays(10).Date.AddHours(18),\n        \"x@example.com\",\n        \"\",\n        1);\n    var mgrTD = new Mock&lt;IReservationsManager&gt;();\n    mgrTD.Setup(mgr =&gt; mgr.TrySave(r)).ReturnsAsync(true);\n    var sut = new RestaurantManager(\n        TimeSpan.FromHours(18),\n        TimeSpan.FromHours(21),\n        mgrTD.Object);\n \n    var actual = await sut.Check(r);\n \n    Assert.True(actual);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>(This C# test uses \u003Ca href=\"https:\u002F\u002Fxunit.net\u002F\">xUnit.net\u003C\u002Fa> 2.4.1 with \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmoq\u002Fmoq4\">Moq\u003C\u002Fa> 4.14.1.)\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Such tests are brittle. They break easily and therefore increase your maintenance burden.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3 id=\"h-why-internal-dependencies-are-bad\">Why internal dependencies are bad\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp id=\"h-as-the-above-unit-test-implies-the-restaurantmanager-relies-on-an-injected-ireservationsmanager-dependency-this-interface-is-an-internal-implementation-detail-think-of-the-entire-application-as-a-blue-box-with-two-objects-as-internal-components\">As the above unit test implies, the \u003Ccode>RestaurantManager\u003C\u002Fcode> relies on an injected \u003Ccode>IReservationsManager\u003C\u002Fcode> dependency. This interface is an internal implementation detail. Think of the entire application as a blue box with two objects as internal components:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:image -->\n\u003Cfigure class=\"wp-block-image\">\u003Cimg src=\"https:\u002F\u002Flh3.googleusercontent.com\u002FE1YJw5Y-d-EyKvKEQvrO1OHVvo44IMFC5lENCGQ-LiukqjHdfbfxU9FoDPxsgLPxbVfqqFtLLEC1JMJPLcXj932qdT7vMmKcFPRT0W2xyugz_PHLkoH21VYLzm5jieSts7GQa-mp\" alt=\"\"\u002F>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:image -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>An application contains many internal building blocks. The above illustration emphasizes two such components, and how they interact with each other.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>What happens if you'd like to refactor the application code? Refactoring often involves changing how internal building blocks interact with each other. For example, you might want to change the \u003Ccode>IReservationsManager\u003C\u002Fcode> interface.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>When you make a change like that, you'll break some of the code that relies on the interface. That's to be expected. Refactoring, after all, involves changing code.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>When your tests also rely on internal implementation details, refactoring also breaks the tests. Now, in addition to improving the internal code, you also have to fix all the tests that broke.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Using a \u003Cem>dynamic mock library\u003C\u002Fem> like \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmoq\u002Fmoq4\">Moq\u003C\u002Fa> tends to amplify the problem. You now have to visit all the tests that configure mocks and adjust them to model the new internal interaction.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This kind of friction is likely to deter you from refactoring in the first place. If you know that a warranted refactoring will give you much extra work fixing tests, you may decide that it isn't worth the trouble. Instead, you leave the production code in a suboptimal state.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Is there a better way?\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3 id=\"h-functional-core\">Functional core\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp id=\"h-in-order-to-find-a-better-alternative-you-must-first-understand-the-problem-why-use-test-doubles-mocks-and-stubs-in-the-first-place\">In order to find a better alternative, you must first understand the problem. Why use test doubles (mocks and stubs) in the first place?\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Test doubles serve a major purpose: They enable us to write deterministic unit tests.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fmartinfowler.com\u002Farticles\u002FnonDeterminism.html\">Unit tests should be deterministic\u003C\u002Fa>. Running a test multiple times should produce the same outcome each time (\u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCeteris_paribus\">ceteris paribus\u003C\u002Fa>). A test that succeeds on a Wednesday shouldn't fail on a Saturday.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>By using a test double each test can control how a dependency behaves. In \u003Ca href=\"http:\u002F\u002Fbit.ly\u002Fworking-effectively-with-legacy-code\">\u003Cem>Working Effectively with Legacy Code\u003C\u002Fem>\u003C\u002Fa>\u003Cem>,\u003C\u002Fem> Michael Feathers likens a test to a \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVise\">vise\u003C\u002Fa>. It's a tool to fix a particular behavior in place.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Test doubles, however, aren't the only way to make tests deterministic.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>A better alternative is to make the production code itself deterministic. Imagine, for example, that you need to write code that calculates the volume of a \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFrustum\">frustum\u003C\u002Fa>. As long as the frustum doesn't change, the volume remains the same number. Such a calculation is entirely deterministic.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Write your production code using mostly deterministic operations. For example, instead of the above \u003Ccode>RestaurantManager\u003C\u002Fcode>, you can write an immutable class with a method like this:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>public bool WillAccept(\n    DateTime now,\n    IEnumerable&lt;Reservation&gt; existingReservations,\n    Reservation candidate)\n{\n    if (existingReservations is null)\n        throw new ArgumentNullException(nameof(existingReservations));\n    if (candidate is null)\n        throw new ArgumentNullException(nameof(candidate));\n    if (candidate.At &lt; now)\n        return false;\n    if (IsOutsideOfOpeningHours(candidate))\n        return false;\n \n    var seating = new Seating(SeatingDuration, candidate.At);\n    var relevantReservations =\n        existingReservations.Where(seating.Overlaps);\n    var availableTables = Allocate(relevantReservations);\n    return availableTables.Any(t =&gt; t.Fits(candidate.Quantity));\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This example, like all code in this article, is from my book \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002Fcode-that-fits-in-your-head\">\u003Cem>Code That Fits in Your Head\u003C\u002Fem>\u003C\u002Fa>. Despite implementing \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002F2020\u002F01\u002F27\u002Fthe-maitre-d-kata\">quite complex business logic\u003C\u002Fa>, it's a \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPure_function\">pure function\u003C\u002Fa>. All the helper methods involved (\u003Ccode>IsOutsideOfOpeningHours\u003C\u002Fcode>, \u003Ccode>Overlaps\u003C\u002Fcode>, \u003Ccode>Allocate\u003C\u002Fcode>, etc.) are also deterministic.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The upshot is that \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002F2015\u002F05\u002F07\u002Ffunctional-design-is-intrinsically-testable\">deterministic operations are easy to test\u003C\u002Fa>. For instance, here's a parametrized test of the happy path:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&#91;Theory, ClassData(typeof(AcceptTestCases))]\npublic void Accept(MaitreD sut, DateTime now, IEnumerable&lt;Reservation&gt; reservations)\n{\n    var r = Some.Reservation.WithQuantity(11);\n    var actual = sut.WillAccept(now, reservations, r);\n    Assert.True(actual);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This code snippet doesn't show the test case data source (\u003Ccode>AcceptTestCases\u003C\u002Fcode>), but it's a small helper class that produces seven test cases that supply values for \u003Ccode>sut\u003C\u002Fcode>, \u003Ccode>now\u003C\u002Fcode>, and \u003Ccode>reservations\u003C\u002Fcode>.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This test method is typical of unit tests of pure functions:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:list {\"ordered\":true} -->\n\u003Col>\u003Cli>Prepare input value(s)\u003C\u002Fli>\u003Cli>Call the function\u003C\u002Fli>\u003Cli>Compare the expected outcome with the actual value\u003C\u002Fli>\u003C\u002Fol>\n\u003C!-- \u002Fwp:list -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>If you recognize \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002F2013\u002F06\u002F24\u002Fa-heuristic-for-formatting-code-according-to-the-aaa-pattern\">that structure as the Arrange Act Assert pattern\u003C\u002Fa>, you're not wrong, but that's not the main point. What's worth noticing is that despite non-trivial business logic, no test doubles (i.e. mocks or stubs) are required. This is one of many advantages of pure functions. Since they are already deterministic, you don't have to introduce artificial seams into the code to enable testing.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Writing most of a code base as deterministic functions is possible, but requires practice. This style of programming is called \u003Cem>functional programming\u003C\u002Fem> (FP), and while it may require effort for object-oriented programmers to shift perspective, it's quite the game changer—both because of the benefits to testing, and for \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002F2021\u002F07\u002F28\u002Freferential-transparency-fits-in-your-head\">other reasons\u003C\u002Fa>.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Even the most idiomatic FP code base, however, must deal with the messy, non-deterministic real world. Where do input values like \u003Ccode>now\u003C\u002Fcode> and \u003Ccode>existingReservations\u003C\u002Fcode> come from?\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3 id=\"h-imperative-shell\">Imperative shell\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp id=\"h-a-typical-functional-architecture-tends-to-resemble-the-ports-and-adapters-architecture-you-implement-all-business-and-application-logic-as-pure-functions-and-push-impure-actions-to-the-edge\">A typical \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002F2018\u002F11\u002F19\u002Ffunctional-architecture-a-definition\">functional architecture\u003C\u002Fa> tends to \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002F2016\u002F03\u002F18\u002Ffunctional-architecture-is-ports-and-adapters\">resemble the Ports and Adapters architecture\u003C\u002Fa>. You implement all business and application logic as pure functions and push impure actions to the edge.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>At the edge, and only at the edge, you allow impure actions to take place. In the example code that runs through \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002Fcode-that-fits-in-your-head\">\u003Cem>Code That Fits in Your Head\u003C\u002Fem>\u003C\u002Fa>, this happens in controllers. For example, this \u003Ccode>TryCreate\u003C\u002Fcode> helper method is defined in a \u003Ccode>ReservationsController\u003C\u002Fcode> class:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>private async Task&lt;ActionResult&gt; TryCreate(\n    Restaurant restaurant,\n    Reservation reservation)\n{\n    using var scope =\n        new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);\n \n    var reservations = await Repository\n        .ReadReservations(restaurant.Id, reservation.At)\n        .ConfigureAwait(false);\n    var now = Clock.GetCurrentDateTime();\n    if (!restaurant.MaitreD.WillAccept(now, reservations, reservation))\n        return NoTables500InternalServerError();\n \n    await Repository.Create(restaurant.Id, reservation)\n        .ConfigureAwait(false);\n \n    scope.Complete();\n \n    return Reservation201Created(restaurant.Id, reservation);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The \u003Ccode>TryCreate\u003C\u002Fcode> method makes use of two impure, injected dependencies: \u003Ccode>Repository\u003C\u002Fcode> and \u003Ccode>Clock\u003C\u002Fcode>.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The \u003Ccode>Repository\u003C\u002Fcode> dependency represents the database that stores reservations, while \u003Ccode>Clock\u003C\u002Fcode> represents some kind of clock. These dependencies aren't arbitrary. They're there to support unit testing of the application's \u003Ca href=\"https:\u002F\u002Fwww.kennethlange.com\u002Ffunctional-core-imperative-shell\u002F\">\u003Cem>imperative shell\u003C\u002Fem>\u003C\u002Fa>, and they have to be injected dependencies exactly because they're sources of non-determinism.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>It's easiest to understand why \u003Ccode>Clock\u003C\u002Fcode> is a source of non-determinism. Every time you ask what time it is, the answer changes. That's non-deterministic, because the textbook definition of determinism is that the same input should always produce the same output.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The same definition applies to databases. You can repeat the same database query, and over time receive different outputs because the state of the database changes. By the definition of determinism, that makes a database non-deterministic: The same input may produce varying outputs.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>You can still unit test the imperative shell, but you don't have to use brittle dynamic mock objects. Instead, use Fakes.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3 id=\"h-fakes\">Fakes\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp id=\"h-in-the-pattern-language-of-xunit-test-patterns-a-fake-is-a-kind-of-test-double-that-could-almost-serve-as-a-real-implementation-of-an-interface-an-in-memory-database-is-a-useful-example\">In the pattern language of \u003Ca href=\"http:\u002F\u002Fbit.ly\u002Fxunitpatterns\">xUnit Test Patterns\u003C\u002Fa>, a fake is a kind of test double that could \u003Cem>almost\u003C\u002Fem> serve as a “real” implementation of an interface. An in-memory “database” is a useful example:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>public sealed class FakeDatabase :\n    ConcurrentDictionary&lt;int, Collection&lt;Reservation&gt;&gt;,\n    IReservationsRepository\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>While implementing \u003Ccode>IReservationsRepository\u003C\u002Fcode>, this test-specific \u003Ccode>FakeDatabase\u003C\u002Fcode> class inherits \u003Ccode>ConcurrentDictionary&lt;int, Collection&lt;Reservation&gt;&gt;\u003C\u002Fcode>, which means it can leverage the dictionary base class to add and remove reservations. Here's the \u003Ccode>Create\u003C\u002Fcode> implementation:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>public Task Create(int restaurantId, Reservation reservation)\n{\n    AddOrUpdate(\n        restaurantId,\n        new Collection&lt;Reservation&gt; { reservation },\n        (_, rs) =&gt; { rs.Add(reservation); return rs; });\n    return Task.CompletedTask;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>And here's the \u003Ccode>ReadReservations\u003C\u002Fcode> implementation:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>public Task&lt;IReadOnlyCollection&lt;Reservation&gt;&gt; ReadReservations(\n    int restaurantId,\n    DateTime min,\n    DateTime max)\n{\n    return Task.FromResult&lt;IReadOnlyCollection&lt;Reservation&gt;&gt;(\n        GetOrAdd(restaurantId, new Collection&lt;Reservation&gt;())\n            .Where(r =&gt; min &lt;= r.At &amp;&amp; r.At &lt;= max).ToList());\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The \u003Ccode>ReadReservations\u003C\u002Fcode> will return the reservations already added to the repository with the \u003Ccode>Create \u003C\u002Fcode>method. Of course, it only works as long as the \u003Ccode>FakeDatabase \u003C\u002Fcode>object remains in memory, but that's sufficient for a unit test:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&#91;Theory]\n&#91;InlineData(1049, 19, 00, \"juliad@example.net\", \"Julia Domna\", 5)]\n&#91;InlineData(1130, 18, 15, \"x@example.com\", \"Xenia Ng\", 9)]\n&#91;InlineData( 956, 16, 55, \"kite@example.edu\", null, 2)]\n&#91;InlineData( 433, 17, 30, \"shli@example.org\", \"Shanghai Li\", 5)]\npublic async Task PostValidReservationWhenDatabaseIsEmpty(\n    int days,\n    int hours,\n    int minutes,\n    string email,\n    string name,\n    int quantity)\n{\n    var at = DateTime.Now.Date + new TimeSpan(days, hours, minutes, 0);\n    var db = new FakeDatabase();\n    var sut = new ReservationsController(\n        new SystemClock(),\n        new InMemoryRestaurantDatabase(Grandfather.Restaurant),\n        db);\n \n    var dto = new ReservationDto\n    {\n        Id = \"B50DF5B1-F484-4D99-88F9-1915087AF568\",\n        At = at.ToString(\"O\"),\n        Email = email,\n        Name = name,\n        Quantity = quantity\n    };\n    await sut.Post(dto);\n \n    var expected = new Reservation(\n        Guid.Parse(dto.Id),\n        at,\n        new Email(email),\n        new Name(name ?? \"\"),\n        quantity);\n    Assert.Contains(expected, db.Grandfather);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This test injects a \u003Ccode>FakeDatabase\u003C\u002Fcode> variable called \u003Ccode>db\u003C\u002Fcode> and ultimately asserts that \u003Ccode>db\u003C\u002Fcode> has the expected state. Since \u003Ccode>db\u003C\u002Fcode> stays in scope for the duration of the test, its behavior is deterministic and consistent.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Using a fake is more robust in the face of change. If you wish to refactor code that involves changes to an interface like \u003Ccode>IReservationsRepository\u003C\u002Fcode>, the only change you'll need to make to the test code is to edit the fake implementation to make sure that it still preserves the invariants of the type. That's one test file you'll have to maintain, rather than the \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FShotgun_surgery\">shotgun surgery\u003C\u002Fa> necessary when using dynamic mock libraries.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3 id=\"h-architectural-dependencies\">Architectural dependencies\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp id=\"h-to-recap-a-functional-core-needs-no-dependency-injection-to-support-unit-testing-because-functions-are-always-testable-being-deterministic-by-definition-only-the-imperative-shell-needs-dependency-injection-to-support-unit-testing\">To recap: A \u003Cem>functional core\u003C\u002Fem> needs no dependency injection to support unit testing, because functions are always testable (being deterministic by definition). Only the \u003Cem>imperative shell\u003C\u002Fem> needs dependency injection to support unit testing.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Which dependencies are required? Every source of non-deterministic behavior and side effects. This tends to correspond to the actual, architectural dependencies of the application in question, with the possible addition of a clock and a random number generator.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The sample system in \u003Ca href=\"https:\u002F\u002Fblog.ploeh.dk\u002Fcode-that-fits-in-your-head\">\u003Cem>Code That Fits in Your Head\u003C\u002Fem>\u003C\u002Fa> has three “real” dependencies: Its database, an SMTP gateway, and the system clock:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:image -->\n\u003Cfigure class=\"wp-block-image\">\u003Cimg src=\"https:\u002F\u002Flh6.googleusercontent.com\u002FgnPpMc68dQQAguJ2s9Iztl8Jh3d9m7FfMdC_ZisVaK7b1u7BB3nzB-T_VOOvlFj5tilG8U-cZv2wnCqARUyBbor5IwTaL6wRX1OuU63TCcx8482PpUcFG4eu6Dmo-jWGji3KbF-5\" alt=\"\"\u002F>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:image -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Apart from the system clock, these dependencies are components you'd also draw when illustrating the overall architecture of the system. The application is an opaque box, its internal organization implementation details, but its “real” dependencies represent other processes that may run somewhere else on the network.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>These dependencies are the ones you may consider to explicitly model. These dependencies you can hide behind interfaces, inject with Constructor Injection, and replace using test doubles. Not mocks, stubs, or spies, but fakes.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3 id=\"h-conclusion\">Conclusion\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp id=\"h-which-dependencies-should-be-present-in-your-code-base\">Which dependencies should be present in your code base?\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Those that represent non-deterministic behavior or side effects. Adding rows to a database. Sending an email. Getting the current time and date. Querying a database.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>These tend to correspond to the architectural dependencies of the system in question. If the application requires a database in order to work correctly, you'll model the database as a polymorphic dependency. If the system must be able to send email, then a messaging gateway interface is warranted.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>In addition to such architectural dependencies, system time and random number generators are the other well-known sources of non-determinism, so model those as explicit dependencies as well.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>That's it. Those are the dependencies you need. The rest are implementation details, likely to make your test code more brittle.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The implication is that a typical system will only have a handful of dependencies.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->","html","2022-01-03T15:16:05.000Z",{"current":1136},"favor-real-dependencies-for-unit-testing",[1138,1146,1150,1154],{"_createdAt":1139,"_id":1140,"_rev":1141,"_type":1142,"_updatedAt":1139,"slug":1143,"title":1145},"2023-05-23T16:43:21Z","wp-tagcat-code-for-a-living","9HpbCsT2tq0xwozQfkc4ih","blogTag",{"current":1144},"code-for-a-living","Code for a Living",{"_createdAt":1139,"_id":1147,"_rev":1141,"_type":1142,"_updatedAt":1139,"slug":1148,"title":1149},"wp-tagcat-dependencies",{"current":1149},"dependencies",{"_createdAt":1139,"_id":1151,"_rev":1141,"_type":1142,"_updatedAt":1139,"slug":1152,"title":1153},"wp-tagcat-testing",{"current":1153},"testing",{"_createdAt":1155,"_id":1156,"_rev":1157,"_system":1158,"_type":1142,"_updatedAt":1161,"description":1162,"slug":1171,"title":1173},"2025-04-24T16:28:57Z","797b8797-6e65-4723-b53f-8bc005305384","IpfPEqg1c3Byvj9RrB3Xaj",{"base":1159},{"id":1156,"rev":1160},"oc42Nphz1oZNOg9ttSv7Tn","2026-05-07T14:43:30Z",[1163],{"_key":1164,"_type":65,"children":1165,"markDefs":1170,"style":107},"bb32f75814b4",[1166],{"_key":1167,"_type":69,"marks":1168,"text":1169},"dbcf27ef29b3",[],"Community-generated articles submitted for your reading pleasure. If you’re interested in seeing your work here, log in with your Stack Overflow account and click the link below. Articles will be licensed under a CC BY-SA 4.0 grant. ",[],{"_type":10,"current":1172},"contributed","The Heap","Favor real dependencies for unit testing",[1176,1182,1188,1194],{"_id":1177,"publishedAt":1178,"slug":1179,"sponsored":12,"title":1181},"28e560af-f0aa-4d46-bd90-f435ad604aa7","2026-06-26T14:00:27.102Z",{"_type":10,"current":1180},"paging-charity-how-can-engineering-leaders-avoid-becoming-bond-villains","Paging Charity! How can engineering leaders avoid becoming Bond villains?",{"_id":1183,"publishedAt":1184,"slug":1185,"sponsored":12,"title":1187},"4b22c2a3-3779-4966-93eb-5230391dbdce","2026-06-23T14:08:58.595Z",{"_type":10,"current":1186},"your-ai-shipped-a-backend-that-boots-that-is-the-whole-problem","Your AI shipped a backend that boots. That is the whole problem.",{"_id":1189,"publishedAt":1190,"slug":1191,"sponsored":12,"title":1193},"5cf362e1-fe7b-45af-b69c-914731c6a052","2026-06-23T14:00:00.000Z",{"_type":10,"current":1192},"the-2026-developer-survey-is-now-open-for-human-developers-only","The 2026 Developer Survey is now open (for human developers only)!",{"_id":1195,"publishedAt":1196,"slug":1197,"sponsored":12,"title":1199},"30b995f7-7cb9-4dd8-bf71-d0685940a32b","2026-06-19T14:00:00.000Z",{"_type":10,"current":1198},"dispatches-from-o-reilly-from-capabilities-to-responsibilities","Dispatches from O'Reilly: From capabilities to responsibilities",{"data":1201,"sourceMap":-1},{"count":1202,"lastTimestamp":1203},26,"2026-06-11T19:02:10Z"]