{"id":53280,"date":"2024-08-21T10:05:00","date_gmt":"2024-08-21T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=53280"},"modified":"2024-08-21T06:26:56","modified_gmt":"2024-08-21T13:26:56","slug":"supercharge-your-testing-experience-with-ms-test-analyzers","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/supercharge-your-testing-experience-with-ms-test-analyzers\/","title":{"rendered":"Supercharge your testing experience with MSTest.Analyzers"},"content":{"rendered":"<p>MSTest ships with a set of analyzers that inspect your test code and point out common mistakes and pitfalls. These mistakes can be subtle and lead to your tests being completely ignored by the test framework.<\/p>\n<p>We\u2019ve been shipping these analyzers since 3.2.0, but in the latest 3.5.1, we\u2019ve added some that we think you should not miss.<\/p>\n<h2>The missing test<\/h2>\n<p>One common problem is when you forget to put <code>[TestClass]<\/code> on your class. MSTest won&#8217;t know that there are tests in the class, and it won&#8217;t run them:<\/p>\n<pre><code class=\"language-cs\">\r\npublic class MyTests\r\n\r\n{\r\n    [TestMethod]\r\n    public async Task TestMethod1()\r\n    {\r\n      Assert.Fail();\r\n    }\r\n}<\/code><\/pre>\n<p>Without MSTest.Analyzers, this code builds without warning or info message. There is no test failure when running the tests either. Because there is no <code>[TestClass]<\/code> attribute on the class, MSTest will skip over the whole class for performance reasons, and your test will never be found.<\/p>\n<p>But with analyzers you get an info message during build:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/08\/info-1.png\" alt=\"Info message for MSTEST0030 shown in Visual Studio Error List\" \/><\/p>\n<p>We recommend, to upgrade this message to a warning, or even build error, one such way is by adding this line to your <code>.editorconfig<\/code>:<\/p>\n<pre><code class=\"language-txt\">[*.cs]\r\n# MSTEST0030: Type containing '[TestMethod]' should be marked with '[TestClass]'\r\ndotnet_diagnostic.MSTEST0030.severity = warning<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/08\/warning-1.png\" alt=\"Warning message for MSTEST0030 shown in Visual Studio Error List\" \/><\/p>\n<h3>Why is this not a warning by default?<\/h3>\n<p>You might be asking why <code>MSTEST0030<\/code> is an info message and not warning by default. The reason is that we cannot introduce breaking changes in MSTest v3, and the code above is a common pattern for re-using tests from a base class.<\/p>\n<pre><code class=\"language-cs\">public class MyTestsBase\r\n{\r\n    [TestMethod]\r\n    public async Task CommonTestMethod()\r\n    {\r\n    }\r\n}\r\n\r\n[TestClass]\r\npublic class MyTests : MyTestsBase\r\n{\r\n    [TestMethod]\r\n    public async Task TestMethod1()\r\n    {\r\n      Assert.Fail();\r\n    }\r\n}<\/code><\/pre>\n<p>In the example above, the test <code>CommonTestMethod<\/code> will not run from <code>MyTestsBase<\/code>, because it does not have <code>[TestClass]<\/code> attribute, but it will be inherited to <code>MyTests<\/code>, and will run there.<\/p>\n<p>We <strong>DO NOT<\/strong> recommend this pattern. Instead, we recommend to always mark classes with <code>[TestClass]<\/code>, and make the base class abstract, if you don\u2019t want to run tests from it.<\/p>\n<pre><code class=\"language-cs\">[TestClass]\r\npublic abstract class MyTestsBase\r\n{\r\n    [TestMethod]\r\n    public async Task CommonTestMethod()\r\n    {\r\n    }\r\n}\r\n\r\n[TestClass]\r\npublic class MyTests : MyTestsBase\r\n{\r\n    [TestMethod]\r\n    public async Task TestMethod1()\r\n    {\r\n      Assert.Fail();\r\n    }\r\n}<\/code><\/pre>\n<p>This approach behaves identically to the one above, but you communicate it clearly to the analyzers and the testing framework that the <code>abstract<\/code> base class is holding a shared logic, and should not run by itself.<\/p>\n<h2>Malformed AssemblyInitialize<\/h2>\n<p>Another example of a useful analyzer is fixing the signature of <code>[AssemblyInitialize]<\/code>, to do a one-time setup for all the tests in the assembly.<\/p>\n<p>I don&#8217;t know about you, but I can&#8217;t remember the signature of this method. And when I get it wrong my tests don&#8217;t run at all. This is especially annoying in Visual Studio, where the test simply remains blue, and I need to go into the <code>Tests<\/code> output to find the reason.<\/p>\n<p>But with the analyzers, I can easily find out what is wrong, and there is even an automatic fix that I can apply to my code.<\/p>\n<p>Here I write method Setup, and VisualStudio will underline it with a warning, and I press <code>Ctrl+.<\/code> to see the automatic fix and apply it:<\/p>\n<pre><code class=\"language-cs\">[TestClass]\r\npublic class MyTests\r\n{\r\n  [AssemblyInitialize]\r\n  public void Setup()\r\n  {\r\n  }\r\n}<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/08\/warning-2.png\" alt=\"Warning message for MSTEST0012 shown in Visual Studio Error List\" \/>\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/08\/code-fix.png\" alt=\"Fixing signature via lightbulb menu\" \/><\/p>\n<p>Fixing my code to the correct shape that the testing framework can recognize:<\/p>\n<pre><code class=\"language-cs\"> [TestClass]\r\n public class MyTests\r\n {\r\n     [AssemblyInitialize]\r\n     public static void Setup(TestContext context)\r\n     {\r\n     }\r\n }<\/code><\/pre>\n<h2>Installation<\/h2>\n<p>The recommended way to start using <code>MSTest.Analyzers<\/code> is by using the <code>MSTest<\/code> nuget package, or the MSTest project SDK, with version 3.2.0 or newer.<\/p>\n<p><a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/testing\/unit-testing-mstest-getting-started\">https:\/\/learn.microsoft.com\/dotnet\/core\/testing\/unit-testing-mstest-getting-started<\/a><\/p>\n<p>The analyzers can also be installed separately by referencing the <code>MSTest.Analyzers<\/code> NuGet package.<\/p>\n<p>We wholeheartedly recommend any project that is using MSTest to upgrade to version 3.2.0 and newer, and enable those analyzers.<\/p>\n<h2>Summary<\/h2>\n<p>The two analyzers showcased in this article are the ones that I find the most useful in my day-to-day. But there is a whole lot more, such as:<\/p>\n<ul>\n<li>MSTEST0003, which ensures that your test method has correct signature, such as being <code>public<\/code>, and not being <code>async void<\/code>.<\/li>\n<li>MSTEST0001, which recommends enabling test parallelization, because we\u2019ve seen multiple test bases dramatically reduce their test execution time by doing so.<\/li>\n<li>MSTEST0017, which ensures that you pass arguments to assertions in the correct order, to avoid confusing test failure messages.<\/li>\n<\/ul>\n<p>And 32 more rules, that are split into Design, Performance, and Usage categories. Helping you to write well formed, performant and error free tests.<\/p>\n<p><a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/testing\/mstest-analyzers\/overview\">https:\/\/learn.microsoft.com\/dotnet\/core\/testing\/mstest-analyzers\/overview<\/a><\/p>\n<p>We are constantly looking for ways to improve these analyzers or new analyzers that our customers are missing. We welcome you to share your feedback, ideas for more analyzers, and your experience, on our repository <a href=\"https:\/\/github.com\/microsoft\/testfx\/issues\">microsoft\/testfx<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>MSTest ships with extensive suite of code analyzers to help you write well-formed, performant and error free tests.<\/p>\n","protected":false},"author":141845,"featured_media":53281,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,756],"tags":[7784,136],"class_list":["post-53280","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-csharp","tag-mstest","tag-testing"],"acf":[],"blog_post_summary":"<p>MSTest ships with extensive suite of code analyzers to help you write well-formed, performant and error free tests.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/53280","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/141845"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=53280"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/53280\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/53281"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=53280"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=53280"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=53280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}