<story><title>Multiple assertions are fine in a unit test</title><url>https://stackoverflow.blog/2022/11/03/multiple-assertions-per-test-are-fine/</url></story><parent_chain><item><author>torginus</author><text>I remember writing a small .NET test library for that exact problem - You could pass in a lambda with a complex condition, and it evaluated every piece of the expression separately and pretty printed what part of the condition failed.&lt;p&gt;So essentially you could write&lt;p&gt;&lt;pre&gt;&lt;code&gt;     Assert(()=&amp;gt;width&amp;gt;0 &amp;amp;&amp;amp; x + width &amp;lt; screenWidth)
&lt;/code&gt;&lt;/pre&gt;
And you would get:&lt;p&gt;&lt;pre&gt;&lt;code&gt;      Assertion failed: 
      x is 1500
      width is 600
      screenWidth is 1920

&lt;/code&gt;&lt;/pre&gt;
It used &lt;i&gt;Expression&amp;lt;T&amp;gt;&lt;/i&gt; to do the magic. Amazing debug messages. No moralizing required.&lt;p&gt;This was a huge boon for us as it was a legacy codebase and we ran tens of thousands of automated tests and it was really difficult to figure out why they failed.</text></item><item><author>TeMPOraL</author><text>&amp;gt; &lt;i&gt;The excellent book xUnit Test Patterns describes a test smell named Assertion Roulette. It describes situations where it may be difficult to determine exactly which assertion caused a test failure.&lt;/i&gt;&lt;p&gt;How is that even possible in the first place?&lt;p&gt;The entire job of an assertion is to wave a flag saying &amp;quot;here! condition failed!&amp;quot;. In programming languages and test frameworks I worked with, this typically includes providing &lt;i&gt;at minimum&lt;/i&gt; the expression put in the assertion, &lt;i&gt;verbatim&lt;/i&gt;, and precise coordinates of the assertion - i.e. name of the source file + line number.&lt;p&gt;I&amp;#x27;ve never seen a case where it would be hard to tell &lt;i&gt;which assertion failed&lt;/i&gt;. On the contrary, the most common problem I see is knowing which assertion failed, but not how the code got there, because someone helpfully stuffed it into a helper function that gets called by other helper functions in the test suite, and the testing framework doesn&amp;#x27;t report the call stack. But it&amp;#x27;s not that big of a deal anyway; the main problem I have with it is that I can&amp;#x27;t gleam the exact source of failure from CI logs, and have to run the thing myself.</text></item></parent_chain><comment><author>paphillips</author><text>Related to this, for anyone not fully up to date on recent C# features there is also the &lt;i&gt;CallerArgumentExpression&lt;/i&gt; [1], [2] feature introduced in C# 10. While it is not a pretty printer for an expression, it does allow the full expression passed from the call site as an argument value to be captured and used within the method. This can be useful for custom assert extensions.&lt;p&gt;For example:&lt;p&gt;&lt;pre&gt;&lt;code&gt;    public void CheckIsTrue(bool value, [CallerArgumentExpression(&amp;quot;value&amp;quot;)] string? expression = null)
    {
        if (!value) 
        { 
            Debug.WriteLine($&amp;quot;Failed: &amp;#x27;{expression}&amp;#x27;&amp;quot;); 
        }
    }
&lt;/code&gt;&lt;/pre&gt;
So if you call like this: &lt;i&gt;CheckIsTrue(foo != bar &amp;amp;&amp;amp; baz == true)&lt;/i&gt;, when the value is false it prints  &amp;quot;Failed: &amp;#x27;foo != bar &amp;amp;&amp;amp; baz == true&amp;#x27;&amp;quot;.&lt;p&gt;[1] &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;learn.microsoft.com&amp;#x2F;en-us&amp;#x2F;dotnet&amp;#x2F;csharp&amp;#x2F;language-reference&amp;#x2F;proposals&amp;#x2F;csharp-10.0&amp;#x2F;caller-argument-expression&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;learn.microsoft.com&amp;#x2F;en-us&amp;#x2F;dotnet&amp;#x2F;csharp&amp;#x2F;language-ref...&lt;/a&gt;
[2] &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;learn.microsoft.com&amp;#x2F;en-us&amp;#x2F;dotnet&amp;#x2F;csharp&amp;#x2F;language-reference&amp;#x2F;attributes&amp;#x2F;caller-information&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;learn.microsoft.com&amp;#x2F;en-us&amp;#x2F;dotnet&amp;#x2F;csharp&amp;#x2F;language-ref...&lt;/a&gt;</text></comment>
<story><title>Multiple assertions are fine in a unit test</title><url>https://stackoverflow.blog/2022/11/03/multiple-assertions-per-test-are-fine/</url></story><parent_chain><item><author>torginus</author><text>I remember writing a small .NET test library for that exact problem - You could pass in a lambda with a complex condition, and it evaluated every piece of the expression separately and pretty printed what part of the condition failed.&lt;p&gt;So essentially you could write&lt;p&gt;&lt;pre&gt;&lt;code&gt;     Assert(()=&amp;gt;width&amp;gt;0 &amp;amp;&amp;amp; x + width &amp;lt; screenWidth)
&lt;/code&gt;&lt;/pre&gt;
And you would get:&lt;p&gt;&lt;pre&gt;&lt;code&gt;      Assertion failed: 
      x is 1500
      width is 600
      screenWidth is 1920

&lt;/code&gt;&lt;/pre&gt;
It used &lt;i&gt;Expression&amp;lt;T&amp;gt;&lt;/i&gt; to do the magic. Amazing debug messages. No moralizing required.&lt;p&gt;This was a huge boon for us as it was a legacy codebase and we ran tens of thousands of automated tests and it was really difficult to figure out why they failed.</text></item><item><author>TeMPOraL</author><text>&amp;gt; &lt;i&gt;The excellent book xUnit Test Patterns describes a test smell named Assertion Roulette. It describes situations where it may be difficult to determine exactly which assertion caused a test failure.&lt;/i&gt;&lt;p&gt;How is that even possible in the first place?&lt;p&gt;The entire job of an assertion is to wave a flag saying &amp;quot;here! condition failed!&amp;quot;. In programming languages and test frameworks I worked with, this typically includes providing &lt;i&gt;at minimum&lt;/i&gt; the expression put in the assertion, &lt;i&gt;verbatim&lt;/i&gt;, and precise coordinates of the assertion - i.e. name of the source file + line number.&lt;p&gt;I&amp;#x27;ve never seen a case where it would be hard to tell &lt;i&gt;which assertion failed&lt;/i&gt;. On the contrary, the most common problem I see is knowing which assertion failed, but not how the code got there, because someone helpfully stuffed it into a helper function that gets called by other helper functions in the test suite, and the testing framework doesn&amp;#x27;t report the call stack. But it&amp;#x27;s not that big of a deal anyway; the main problem I have with it is that I can&amp;#x27;t gleam the exact source of failure from CI logs, and have to run the thing myself.</text></item></parent_chain><comment><author>nerdponx</author><text>This is what the Python test framework Pytest does, among many other similar useful and magical things. I believe that the Python developer ecosystem as a whole would be substantially less productive without it.</text></comment>