{"id":179,"date":"2011-01-31T17:14:00","date_gmt":"2011-01-31T17:14:00","guid":{"rendered":"https:\/\/pagan-gerbil.net\/?p=179"},"modified":"2011-01-31T17:14:00","modified_gmt":"2011-01-31T17:14:00","slug":"learning-unit-testing-viii-emergent-design","status":"publish","type":"post","link":"https:\/\/www.pagan-gerbil.net\/?p=179","title":{"rendered":"Learning Unit Testing VIII &#8211; Emergent Design"},"content":{"rendered":"<p>I\u2019ve been bracing myself for this moment since I started the project \u2013 I\u2019m coming to believe that I\u2019ve been heading in a slightly wrong direction.<\/p>\n<p>Part of TDD is the idea of \u2018emergent design\u2019, and letting the correct design emerge from the process of writing minimal code to pass tests. At the same time, it\u2019s necessary to keep an eye on the bigger picture so you know where exactly the code should be written.<\/p>\n<p>I\u2019ve been making the MoveModel method into a huge monster, that checks all sorts of things, and as I started investigating how to implement line of sight, I realised that this functionality should probably be moved out into some sort of utility class. MoveModel itself is now checking distances between two points (this will be duplicated later), proximity detection (probably to be used later), and as I said \u2013 was about to take on line of sight. All these details could be worked out mathematically as I was doing them, but some frameworks (such as XNA) might provide better ways to calculate them, with things such as Rays, or&#8230; something else XNAish.<\/p>\n<p>The best way to handle that would be to refactor all the \u2018utility\u2019 calculations into a separate class, exposed via an interface so that it can be swapped out. That way, I can abstract out and mock all the calculations in MoveModel to deal more with the situation parameters and appropriate responses and less about the calculations themselves. At the same time, I can write tests for this new utility class so that I can test the purely mathematical aspects of the same calculations. The interactions become easier (true, false, and integer responses rather than the broad spectrum of mathematical output) since I don\u2019t have to test multiple configurations <em>and<\/em> situation-specific responses, just the two separate things that should be behaving.<\/p>\n<p>The other benefit will be that if I eventually do take this library over to an XNA frontend, I can swap out that mathematical calculator for something more efficient for the framework to use. But the basic mathematical way will still be available if I choose instead to port it to Silverlight.<\/p>\n<p>I also took this opportunity to move the X, Y and Z co-ordinates into a separate class \u2013 LocationPoint.<\/p>\n<p>Here\u2019s the set of tests for MoveModel:<\/p>\n<pre class=\"code\">[<span style=\"color: #2b91af\">TestClass<\/span>]\n<span style=\"color: blue\">public class <\/span><span style=\"color: #2b91af\">ModelTests\n<\/span>{\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>NewTurn_SetsDistanceMovedToZero()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\ntestModel.TotalDistanceMoved = 4;\ntestModel.NewTurn();\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.TotalDistanceMoved);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_PositionHasChanged()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;());\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">float <\/span>newX = 2;\n<span style=\"color: blue\">float <\/span>newY = 2;\n<span style=\"color: blue\">float <\/span>newZ = 2;\ntestModel.MoveModel(newX, newY, newZ);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(2, testModel.Location.X);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(2, testModel.Location.Y);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(2, testModel.Location.Z);\n<span style=\"color: #2b91af\">Assert<\/span>.IsFalse(testModel.IsRunning);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_TotalMovementInASingleTurnCannotExceedModelMovement_ThrowsMovementException()\n{\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;());\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">float <\/span>newX = 5;\n<span style=\"color: blue\">float <\/span>newY = 4;\n<span style=\"color: blue\">float <\/span>newZ = 3;\ntestModel.MoveModel(newX, newY, newZ);\n<span style=\"color: blue\">try\n<\/span>{\ntestModel.MoveModel(0, 0, 0);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsTrue(correctExceptionThrown);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_MakeTwoSmallMovementsWithoutGoingOverMovementRate()\n{\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;());\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">float <\/span>newX = 1;\n<span style=\"color: blue\">float <\/span>newY = 1;\n<span style=\"color: blue\">float <\/span>newZ = 0;\n<span style=\"color: blue\">try\n<\/span>{\ntestModel.MoveModel(newX, newY, newZ);\ntestModel.MoveModel(0, 0, 0);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsFalse(correctExceptionThrown);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_CannotMoveFurtherThanModelsMovement()\n{\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\n<span style=\"color: blue\">float <\/span>newX = 5;\n<span style=\"color: blue\">float <\/span>newY = 6;\n<span style=\"color: blue\">float <\/span>newZ = 3;\n<span style=\"color: blue\">try\n<\/span>{\ntestModel.MoveModel(newX, newY, newZ);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsTrue(correctExceptionThrown);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_MovesDistanceOverMovementRateAndSetsIsRunningFlag()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;());\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">float <\/span>newX = 5;\n<span style=\"color: blue\">float <\/span>newY = 4;\n<span style=\"color: blue\">float <\/span>newZ = 3;\ntestModel.MoveModel(newX, newY, newZ);\n<span style=\"color: #2b91af\">Assert<\/span>.IsTrue(testModel.IsRunning);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_StopsRunningWithin8InchesOfEnemyModel()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>enemyModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\nenemyModel.Location.X = 9;\nenemyModel.Location.Y = 0;\nenemyModel.Location.Z = 0;\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;() { enemyModel });\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(2, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: blue\">try\n<\/span>{\nmockObjectManager.Setup(item =&gt; item.GetDistanceBetween(testModel.Location, <span style=\"color: #2b91af\">It<\/span>.IsAny&lt;<span style=\"color: blue\">float<\/span>&gt;(), <span style=\"color: #2b91af\">It<\/span>.IsAny&lt;<span style=\"color: blue\">float<\/span>&gt;(), <span style=\"color: #2b91af\">It<\/span>.IsAny&lt;<span style=\"color: blue\">float<\/span>&gt;())).Returns(8);\nmockObjectManager.Setup(item =&gt; item.GetPointOfIntersection(testModel.Location, <span style=\"color: #2b91af\">It<\/span>.IsAny&lt;<span style=\"color: #2b91af\">LocationPoint<\/span>&gt;(), enemyModel.Location, 8)).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">LocationPoint<\/span>(1, 0, 0));\nmockObjectManager.Setup(item =&gt; item.GetLineOfSight(testModel, enemyModel)).Returns(1);\ntestModel.MoveModel(8, 0, 0);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(1, ex.FinalPosition.X);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, ex.FinalPosition.Y);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, ex.FinalPosition.Z);\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsTrue(correctExceptionThrown);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(1, testModel.Location.X);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Y);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Z);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_ContinuesRunningWithEnemyMoreThan8InchesAway()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>enemyModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\nenemyModel.Location.X = 18;\nenemyModel.Location.Y = 0;\nenemyModel.Location.Z = 0;\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;() { enemyModel });\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(2, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: blue\">try\n<\/span>{\ntestModel.MoveModel(8, 0, 0);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsFalse(correctExceptionThrown);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(8, testModel.Location.X);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Y);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Z);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_ContinuesMovingWithin8InchesOfEnemyModelNotRunning()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>enemyModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\nenemyModel.Location.X = 9;\nenemyModel.Location.Y = 0;\nenemyModel.Location.Z = 0;\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;() { enemyModel });\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(2, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: blue\">try\n<\/span>{\ntestModel.MoveModel(3, 0, 0);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsFalse(correctExceptionThrown);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(3, testModel.Location.X);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Y);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Z);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_ContinuesRunningWithin8InchesOfFriendlyModel()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>friendlyModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\nfriendlyModel.Location.X = 9;\nfriendlyModel.Location.Y = 0;\nfriendlyModel.Location.Z = 0;\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;() { friendlyModel });\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: blue\">try\n<\/span>{\ntestModel.MoveModel(8, 0, 0);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsFalse(correctExceptionThrown);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(8, testModel.Location.X);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Y);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Z);\n}\n[<span style=\"color: #2b91af\">TestMethod<\/span>]\n<span style=\"color: blue\">public void <\/span>MoveModel_ContinuesRunningWithin8InchesOfEnemyModelIfOutOfSight()\n{\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt; mockGameManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IGameManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt; mockObjectManager = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IObjectManager<\/span>&gt;();\n<span style=\"color: #2b91af\">Model <\/span>enemyModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(1, mockGameManager.Object, mockObjectManager.Object);\nenemyModel.Location.X = 12;\nenemyModel.Location.Y = 0;\nenemyModel.Location.Z = 0;\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;() { enemyModel });\n<span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IScenery<\/span>&gt; mockScenery = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Mock<\/span>&lt;<span style=\"color: #2b91af\">IScenery<\/span>&gt;();\nmockScenery.Setup(item =&gt; item.IsBlocking(<span style=\"color: #2b91af\">It<\/span>.IsAny&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;(), <span style=\"color: #2b91af\">It<\/span>.IsAny&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;())).Returns(<span style=\"color: blue\">true<\/span>);\nmockGameManager.Setup(item =&gt; item.Models).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IModel<\/span>&gt;() { enemyModel });\nmockGameManager.Setup(item =&gt; item.SceneryObjects).Returns(<span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">List<\/span>&lt;<span style=\"color: #2b91af\">IScenery<\/span>&gt;() { mockScenery.Object });\n<span style=\"color: #2b91af\">Model <\/span>testModel = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">Model<\/span>(2, mockGameManager.Object, mockObjectManager.Object);\ntestModel.Movement = 4;\ntestModel.Location.X = 0;\ntestModel.Location.Y = 0;\ntestModel.Location.Z = 0;\n<span style=\"color: blue\">bool <\/span>correctExceptionThrown = <span style=\"color: blue\">false<\/span>;\n<span style=\"color: blue\">try\n<\/span>{\ntestModel.MoveModel(8, 0, 0);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">MovementException <\/span>ex)\n{\ncorrectExceptionThrown = <span style=\"color: blue\">true<\/span>;\n}\n<span style=\"color: #2b91af\">Assert<\/span>.IsFalse(correctExceptionThrown);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(8, testModel.Location.X);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Y);\n<span style=\"color: #2b91af\">Assert<\/span>.AreEqual(0, testModel.Location.Z);\n}\n}<\/pre>\n<p>And the code needed in MoveModel itself:<\/p>\n<pre class=\"code\"><span style=\"color: blue\">public void <\/span>MoveModel(<span style=\"color: blue\">float <\/span>positionX, <span style=\"color: blue\">float <\/span>positionY, <span style=\"color: blue\">float <\/span>positionZ)\n{\n<span style=\"color: blue\">try\n<\/span>{\nValidateMove(<span style=\"color: blue\">ref <\/span>positionX, <span style=\"color: blue\">ref <\/span>positionY, <span style=\"color: blue\">ref <\/span>positionZ);\n}\n<span style=\"color: blue\">catch <\/span>(<span style=\"color: #2b91af\">Exception <\/span>ex)\n{\n<span style=\"color: blue\">throw<\/span>;\n}\n<span style=\"color: blue\">finally\n<\/span>{\n<span style=\"color: blue\">this<\/span>.TotalDistanceMoved += GetDistanceFrom(positionX, positionY, positionZ);\n<span style=\"color: blue\">this<\/span>.Location.X = positionX;\n<span style=\"color: blue\">this<\/span>.Location.Y = positionY;\n<span style=\"color: blue\">this<\/span>.Location.Z = positionZ;\n<span style=\"color: blue\">if <\/span>(<span style=\"color: blue\">this<\/span>.TotalDistanceMoved &gt; <span style=\"color: blue\">this<\/span>.Movement)\n{\n<span style=\"color: blue\">this<\/span>.IsRunning = <span style=\"color: blue\">true<\/span>;\n}\n}\n}\n<span style=\"color: blue\">private bool <\/span>ValidateMove(<span style=\"color: blue\">ref float <\/span>positionX, <span style=\"color: blue\">ref float <\/span>positionY, <span style=\"color: blue\">ref float <\/span>positionZ)\n{\n<span style=\"color: blue\">double <\/span>distanceToPoint = GetDistanceFrom(positionX, positionY, positionZ);\n<span style=\"color: blue\">if <\/span>(distanceToPoint + <span style=\"color: blue\">this<\/span>.TotalDistanceMoved &gt; <span style=\"color: blue\">this<\/span>.Movement * 2)\n{\n<span style=\"color: #2b91af\">MovementException <\/span>ex = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">MovementException<\/span>(<span style=\"color: #a31515\">\"The model cannot move further than it's Movement rate.\"<\/span>);\nex.FinalPosition.X = <span style=\"color: blue\">this<\/span>.Location.X;\nex.FinalPosition.Y = <span style=\"color: blue\">this<\/span>.Location.Y;\nex.FinalPosition.Z = <span style=\"color: blue\">this<\/span>.Location.Z;\n<span style=\"color: blue\">throw <\/span>ex;\n}\n<span style=\"color: blue\">if <\/span>(<span style=\"color: blue\">this<\/span>.TotalDistanceMoved + distanceToPoint &gt; <span style=\"color: blue\">this<\/span>.Movement)\n{\n<span style=\"color: blue\">foreach <\/span>(<span style=\"color: #2b91af\">IModel <\/span>enemyModel <span style=\"color: blue\">in <\/span>_gameManager.Models.Where(item =&gt; item.Player != <span style=\"color: blue\">this<\/span>.Player))\n{\n<span style=\"color: #2b91af\">LocationPoint <\/span>intersectionPoint = _objectManager.GetPointOfIntersection(<span style=\"color: blue\">this<\/span>.Location, <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">LocationPoint<\/span>(positionX, positionY, positionZ), enemyModel.Location, 8);\n<span style=\"color: blue\">if <\/span>(intersectionPoint != <span style=\"color: blue\">null<\/span>)\n{\n<span style=\"color: blue\">if <\/span>(_objectManager.GetLineOfSight(<span style=\"color: blue\">this<\/span>, enemyModel) &gt; 0)\n{\n<span style=\"color: #2b91af\">MovementException <\/span>ex = <span style=\"color: blue\">new <\/span><span style=\"color: #2b91af\">MovementException<\/span>(<span style=\"color: #a31515\">\"The model cannot run within 8\\\" of an enemy model.\"<\/span>);\nex.FinalPosition = intersectionPoint;\npositionX = intersectionPoint.X;\npositionY = intersectionPoint.Y;\npositionZ = intersectionPoint.Z;\n<span style=\"color: blue\">throw <\/span>ex;\n}\n}\n}\n}\n<span style=\"color: blue\">return true<\/span>;\n}<\/pre>\n<p>The lesson I\u2019ve learned from this as far as emergent design goes is that I should be more willing to abstract something out if it doesn\u2019t look like it belongs, and be prepared to program against interfaces that are not implemented yet. I believe that\u2019s the way TDD works, and will keep code exactly where it needs to be and not spread around (as it was starting to do in the Model class&#8230;)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I\u2019ve been bracing myself for this moment since I started the project \u2013 I\u2019m coming to believe that I\u2019ve been heading in a slightly wrong direction. Part of TDD is the idea of \u2018emergent design\u2019, and letting the correct design emerge from the process of writing minimal code to pass tests. At the same time, &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.pagan-gerbil.net\/?p=179\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Learning Unit Testing VIII &#8211; Emergent Design&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[43,62,63,64],"series":[73],"_links":{"self":[{"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=\/wp\/v2\/posts\/179"}],"collection":[{"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=179"}],"version-history":[{"count":0,"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=\/wp\/v2\/posts\/179\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=179"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=179"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=179"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/www.pagan-gerbil.net\/index.php?rest_route=%2Fwp%2Fv2%2Fseries&post=179"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}