Skip to content

Commit

Permalink
Improved readability of HTML in page
Browse files Browse the repository at this point in the history
This is only for my own benefit, hopefully making it easier to edit the
page.
  • Loading branch information
ploeh committed Mar 7, 2019
1 parent aa6d46d commit 0071504
Showing 1 changed file with 41 additions and 14 deletions.
55 changes: 41 additions & 14 deletions _posts/2009-03-05-ConstrainedNon-Determinism.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
{% include JB/setup %}

<div id="post">
<p>This may turn out to be the most controversial of my <a href="http://blog.ploeh.dk/2009/01/28/Zero-FrictionTDD">Zero-Friction TDD</a> posts so far, as it supposedly goes against conventional wisdom. However, I have found this approach to be really powerful since I began using it about a year ago.</p> <p>In my previous post, I explained how <a href="http://blog.ploeh.dk/2009/03/03/DerivedValuesEnsureExecutableSpecification">Derived Values help ensure that tests act as Executable Specification</a>. In short, a test should clearly specify the relationship between input and outcome, as this test does:</p>
<p>
This may turn out to be the most controversial of my <a href="http://blog.ploeh.dk/2009/01/28/Zero-FrictionTDD">Zero-Friction TDD</a> posts so far, as it supposedly goes against conventional wisdom. However, I have found this approach to be really powerful since I began using it about a year ago.
</p>
<p>
In my previous post, I explained how <a href="http://blog.ploeh.dk/2009/03/03/DerivedValuesEnsureExecutableSpecification">Derived Values help ensure that tests act as Executable Specification</a>. In short, a test should clearly specify the relationship between input and outcome, as this test does:
</p>
<p>
<pre>[<span style="color: #2b91af">TestMethod</span>]
<span style="color: blue">public</span> <span style="color: blue">void</span> InvertWillReverseText()
Expand All @@ -25,9 +30,13 @@
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #a31515">"DoWork"</span>);
&nbsp;&nbsp;&nbsp; <span style="color: green">// Teardown</span>
}</pre>
</p>
<p>However, it is very tempting to just hardcode the expected value. Consistently using <a href="http://blog.ploeh.dk/ct.ashx?id=bab36bea-feb3-436b-a2e2-2860324b704c&amp;url=http%3a%2f%2fxunitpatterns.com%2fDerived%2520Value.html">Derived Values</a> to establish the relationship between input and outcome requires discipline. </p>
<p>To help myself enforce this discipline, I use well-defined, but essentially random, input, because when the input is random, I don't know the value at design time, and hence, it is impossible for me to accidentally hard-code any assertions.</p>
</p>
<p>
However, it is very tempting to just hardcode the expected value. Consistently using <a href="http://blog.ploeh.dk/ct.ashx?id=bab36bea-feb3-436b-a2e2-2860324b704c&amp;url=http%3a%2f%2fxunitpatterns.com%2fDerived%2520Value.html">Derived Values</a> to establish the relationship between input and outcome requires discipline.
</p>
<p>
To help myself enforce this discipline, I use well-defined, but essentially random, input, because when the input is random, I don't know the value at design time, and hence, it is impossible for me to accidentally hard-code any assertions.
</p>
<p>
<pre>[<span style="color: #2b91af">TestMethod</span>]
<span style="color: blue">public</span> <span style="color: blue">void</span> InvertWillReverseText_Cnd()
Expand All @@ -44,16 +53,34 @@
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #a31515">"DoWork"</span>);
&nbsp;&nbsp;&nbsp; <span style="color: green">// Teardown</span>
}</pre>
</p>
<p>For strings, I prefer Guids, as the above example demonstrates. For numbers, I often just use the sequence of natural numbers (i.e. <em>1, 2, 3, 4, 5...</em>). For booleans, I often use an alternating sequence (i.e. <em>true, false, true, false...</em>).</p>
<p>While this technique causes input to become non-deterministic, I always pick the non-deterministic value-generating algorithm in such a way that it creates 'nice' values; I call this principle <strong>Constrained Non-Determinism</strong>. Values are carefully generated to stay far away from any boundary conditions that may cause the <a href="http://blog.ploeh.dk/ct.ashx?id=bab36bea-feb3-436b-a2e2-2860324b704c&amp;url=http%3a%2f%2fxunitpatterns.com%2fSUT.html">SUT</a> to behave differently in each test run.</p>
<p>Conventional unit testing wisdom dictates that unit tests should be deterministic, so how can I possibly endorse this technique?</p>
<p>To understand this, it's important to know <em>why</em> the rule about deterministic unit tests exist. It exists because we want to be certain that each time we execute a test suite, we verify the exact same behavior as we did the last time (given that no tests changed). Since we also use test suites as regression tests, it's important that we can be confident that each and every test run verifies the exact same <em>specification</em>.</p>
<p>Constrained Non-Determinism doesn't invalidate that goal, because the algorithm that generates the values must be carefully picked to always create values that stay within the input's <a href="http://xunitpatterns.com/equivalence%20class.html">Equivalence Class</a>.</p>
<p>In a surprisingly large set of APIs, strings, for example, are treated as opaque values that don't influence behavior in themselves. Many enterprise applications mostly store and read data from persistent data stores, and the value of a string in itself is often inconsequential from the point of view of the code's execution path. Data stores may have constraints on the length of strings, so Constrained Non-Determinism dictates that you should pick the generating algorithm so that the string length always stays within (or exceeds, if that's what you want to test) the constraint. Guid.ToString always returns a string with the length of 36, which is fine for a large number of scenarios.</p>
<p>Note that Constrained Non-Determinism is only relevant for <a href="http://blogs.msdn.com/ploeh/archive/2008/11/17/anonymous-variables.aspx">Anonymous Variables</a>. For input where the value holds a particular meaning in the context of the SUT, you will still need to hand-pick values as always. E.g. if the input is expected to be an XML string conforming to a particular schema, a Guid string makes no sense.</p>
<p>A secondary benefit of Constrained Non-Determinism is that you don't have to pause to come up with values for Anonymous Variables when you are writing the test.</p>
<p>While this advice may be controversial, I can only recommend it - I've been using this technique for about a year now, and have only become more fond of it as I have gained more experience with it.</p>
</p>
<p>
For strings, I prefer Guids, as the above example demonstrates. For numbers, I often just use the sequence of natural numbers (i.e. <em>1, 2, 3, 4, 5...</em>). For booleans, I often use an alternating sequence (i.e. <em>true, false, true, false...</em>).
</p>
<p>
While this technique causes input to become non-deterministic, I always pick the non-deterministic value-generating algorithm in such a way that it creates 'nice' values; I call this principle <strong>Constrained Non-Determinism</strong>. Values are carefully generated to stay far away from any boundary conditions that may cause the <a href="http://blog.ploeh.dk/ct.ashx?id=bab36bea-feb3-436b-a2e2-2860324b704c&amp;url=http%3a%2f%2fxunitpatterns.com%2fSUT.html">SUT</a> to behave differently in each test run.
</p>
<p>
Conventional unit testing wisdom dictates that unit tests should be deterministic, so how can I possibly endorse this technique?
</p>
<p>
To understand this, it's important to know <em>why</em> the rule about deterministic unit tests exist. It exists because we want to be certain that each time we execute a test suite, we verify the exact same behavior as we did the last time (given that no tests changed). Since we also use test suites as regression tests, it's important that we can be confident that each and every test run verifies the exact same <em>specification</em>.
</p>
<p>
Constrained Non-Determinism doesn't invalidate that goal, because the algorithm that generates the values must be carefully picked to always create values that stay within the input's <a href="http://xunitpatterns.com/equivalence%20class.html">Equivalence Class</a>.
</p>
<p>
In a surprisingly large set of APIs, strings, for example, are treated as opaque values that don't influence behavior in themselves. Many enterprise applications mostly store and read data from persistent data stores, and the value of a string in itself is often inconsequential from the point of view of the code's execution path. Data stores may have constraints on the length of strings, so Constrained Non-Determinism dictates that you should pick the generating algorithm so that the string length always stays within (or exceeds, if that's what you want to test) the constraint. Guid.ToString always returns a string with the length of 36, which is fine for a large number of scenarios.
</p>
<p>
Note that Constrained Non-Determinism is only relevant for <a href="http://blogs.msdn.com/ploeh/archive/2008/11/17/anonymous-variables.aspx">Anonymous Variables</a>. For input where the value holds a particular meaning in the context of the SUT, you will still need to hand-pick values as always. E.g. if the input is expected to be an XML string conforming to a particular schema, a Guid string makes no sense.
</p>
<p>
A secondary benefit of Constrained Non-Determinism is that you don't have to pause to come up with values for Anonymous Variables when you are writing the test.
</p>
<p>
While this advice may be controversial, I can only recommend it - I've been using this technique for about a year now, and have only become more fond of it as I have gained more experience with it.
</p>
</div>

<div id="comments">
Expand Down

0 comments on commit 0071504

Please sign in to comment.