<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://blog.aabech.no/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Lars-Erik's blog</title>
    <link>https://blog.aabech.no/</link>
    <description>Ramblings about Umbraco, .net and JavaScript development. With a sprinkle of other stuff.</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <item>
      <guid isPermaLink="false">1216</guid>
      <link>https://blog.aabech.no/archive/more-efficient-integration-tests-with-umbraco/</link>
      <category>umbraco</category>
      <category>unit testing</category>
      <title>More efficient integration tests with Umbraco</title>
      <description>&lt;h2&gt;TLDR;&lt;/h2&gt;
&lt;p&gt;I made &lt;a href="https://www.nuget.org/packages/Umbraco.Community.Integration.Tests.Extensions"&gt;a package&lt;/a&gt; that removes the &amp;quot;database and Umbraco instance&amp;quot; per fixture constraint from &lt;a href="https://www.nuget.org/packages/Umbraco.Cms.Tests.Integration/"&gt;Umbraco's Integration Test library&lt;/a&gt;. It also enables reuse of seeded database snapshots to avoid executing the same setup / seeding over an over per fixture or test.&lt;/p&gt;
&lt;h2&gt;An itch&lt;/h2&gt;
&lt;p&gt;I've spent way too long waiting for similar setup code for my integration tests the last couple of years. The modern .NET version of &lt;a href="https://www.nuget.org/packages/Umbraco.Cms.Tests.Integration/"&gt;Umbraco's integration test library&lt;/a&gt; is super nice, and real effective with SQLite. But it's got a few constraints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All things Umbraco is instantiated and spun up per test, granted a configurable amount.&lt;/li&gt;
&lt;li&gt;Databases have to be &amp;quot;installed&amp;quot; and seeded for each TestFixture at the least.&lt;/li&gt;
&lt;li&gt;All test fixtures need to inherit from Umbraco's base classes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So we spend a long time waiting for suff, even if it's only the little green box we care about:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1072/initial-umbraco-test-sequence.png" alt="Diagram of the hierarchy of a basic Umbraco integration test" /&gt;&lt;/p&gt;
&lt;p&gt;We're also stuck either juggling a singleton of some sorts and/or stuffing a lot of &amp;quot;units&amp;quot; into the same fixture.&lt;br /&gt;
Any notion of intermediate base classes quickly become a sore spot.&lt;/p&gt;
&lt;h2&gt;An idea&lt;/h2&gt;
&lt;p&gt;I had recently discovered, likely for the n-th time in my life, that NUnit supports namespace scoped setup fixtures. Those live as long as all that other tests in that namespace and deeper. They bring an opportunity to share initial state across several fixtures. I often find it nice to have several fixtures for the same systems under tests because it makes sense to group by use-case rather than tech.&lt;/p&gt;
&lt;p&gt;So I set out to see if I could hack together something that made Umbraco's base tests possible to use as setup fixtures rather than &amp;quot;base&amp;quot; fixtures. As things would have it it was early october, and the &lt;a href="https://candidcontributions.com/"&gt;CanCon gang hosted a virtual hackathon&lt;/a&gt; on a friday. I took the day &amp;quot;off&amp;quot; regular work and gave it a go.&lt;/p&gt;
&lt;h2&gt;Dark magic&lt;/h2&gt;
&lt;p&gt;In the end I've used all the dirty tricks you can imagine in today's .NET landscape. You'll find &lt;a href="https://www.nuget.org/packages/Lib.Harmony"&gt;Lib.Harmony&lt;/a&gt; for messing with Umbraco's tests' IL (Intermediate Language), and there's &lt;a href="https://www.nuget.org/packages/Castle.Core"&gt;Castle DynamicProxy&lt;/a&gt; doing a lot of fooling around with the NUnit test hierarchy. The Harmony bit can likely be removed by making a few slight changes to Umbraco's test core, but I wanted to get this working satisfactory before suggesting such changes.&lt;/p&gt;
&lt;p&gt;The bottom line is that those two tools let us run code before, after or even instead of inherited code. And that in turn enables all the following features.&lt;/p&gt;
&lt;h2&gt;A new way of composing tests&lt;/h2&gt;
&lt;p&gt;With the package I've cooked together we can leave the dark world of peach and purple above in favor of a way greener scenery like such:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1071/improved-umbraco-test-sequence.png" alt="Diagram of the hierarchy of an improved Umbraco integration test suite" /&gt;&lt;/p&gt;
&lt;p&gt;So without further ado, let's dig into how you can get there too.&lt;/p&gt;
&lt;h2&gt;Umbraco's attributes&lt;/h2&gt;
&lt;p&gt;We rely on Umbraco's &lt;code&gt;Tests:Database&lt;/code&gt; config and the &lt;code&gt;[UmbracoTest]&lt;/code&gt; attribute to provide databases (or not). The &lt;code&gt;Database&lt;/code&gt; option works almost as expected, but the four non-none options end up doing the same: they prepare &lt;em&gt;one&lt;/em&gt; db for the lifetime of the setup fixture.&lt;/p&gt;
&lt;h2&gt;[ExtendableSetUpFixture]&lt;/h2&gt;
&lt;p&gt;The first attribute you have to know is &lt;code&gt;[ExtendableSetUpFixture]&lt;/code&gt;. It's sole purpose is to enable the rest of them. Since it's inherited from &lt;code&gt;[SetUpFixture]&lt;/code&gt;, it tells NUnit we won't add any &lt;code&gt;[SetUp]&lt;/code&gt;, &lt;code&gt;[TearDown]&lt;/code&gt; or &lt;code&gt;[Test]&lt;/code&gt; methods in the marked class. But this is the attribute we'll add to any &lt;code&gt;UmbracoIntegrationTest&lt;/code&gt; or &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt;, and those have a bunch of each. That's why we have...&lt;/p&gt;
&lt;h2&gt;[MakeOneTimeLifecycle]&lt;/h2&gt;
&lt;p&gt;The first attribute in the package that &lt;em&gt;does something&lt;/em&gt;. &lt;code&gt;[MakeOneTimeLifecycle]&lt;/code&gt; lets you mark methods in otherwise not accessible base classes like &lt;code&gt;UmbracoTestBase&lt;/code&gt; to become &lt;code&gt;[OneTimeSetUp]&lt;/code&gt; methods rather than &lt;code&gt;[SetUp]&lt;/code&gt; methods, and &lt;code&gt;[TearDown]&lt;/code&gt; methods becomes &lt;code&gt;[OneTimeTearDown]&lt;/code&gt;.&lt;br /&gt;
Here's an example of what we'd feed it for an &lt;code&gt;UmbracoIntegrationTest&lt;/code&gt; inheritor:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UmbracoTest(Database=SchemaPerFixture, Boot=true)]
[ExtendableSetUpFixture]
[MakeOneTimeLifecycle(
    setUpNames: [nameof(UmbracoIntegrationTest.Setup), nameof(UmbracoIntegrationTest.SetUp_Logging)],
    tearDownNames: [
        nameof(UmbracoIntegrationTest.TearDown), nameof(UmbracoIntegrationTest.TearDownAsync), 
        nameof(UmbracoIntegrationTest.FixtureTearDown), nameof(UmbracoIntegrationTest.TearDown_Logging)
    ]
)]
public class MyLongLivedUmbracoSetUp : UmbracoIntegrationTest
{
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I found it a bother to write that long attribute all the time, so there's a derived one called:&lt;/p&gt;
&lt;h2&gt;[OneTimeUmbracoSetUp]&lt;/h2&gt;
&lt;p&gt;It makes it slightly less messy by letting us write as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UmbracoTest(Database=SchemaPerFixture, Boot=true)]
[ExtendableSetUpFixture]
[OneTimeUmbracoSetUp]
public class MyLongLivedUmbracoSetUp : UmbracoIntegrationTest
{
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note however that the current version doesn't come with a 100% compatible one for &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt; or &lt;code&gt;ManagementApiTest&amp;lt;&amp;gt;&lt;/code&gt;, but it's easy to make one yourself, and they're likely suddenly in the package.&lt;/p&gt;
&lt;p&gt;Now if you're into hacking around the environment and hidden, protected members lurking around in memory, we're quite alike. But when doing professional work that's often not what we're paid for. So even though the above code will start up a perfectly fine Umbraco instance with a SQLite database it doesn't do much good. We need to get at the &lt;code&gt;IServiceProvider&lt;/code&gt; somehow...&lt;/p&gt;
&lt;h2&gt;[InjectionProvider(string)] and [ServiceProvider]&lt;/h2&gt;
&lt;p&gt;There is a limit to how many attributes we'll stick on our setup fixtures, I promise. I complained about intermediate base classes earlier, but a few for attribute consolidation is cool enough. OK, these two are a basic re-usable one and a &amp;quot;defaulted&amp;quot; one. The &lt;code&gt;[InjectionProvider(string)]&lt;/code&gt; attribute stores a reference to a property on the setup fixture that exposes an &lt;code&gt;IServiceProvider&lt;/code&gt; instance. Umbraco's base classes exposea property called &lt;code&gt;Services&lt;/code&gt;, and &lt;code&gt;[ServiceProvider]&lt;/code&gt; is just a derived &lt;code&gt;[InjectionProvider(nameof(Services))]&lt;/code&gt;. To be specific, the service provider reference goes into the test context property bag as a factory method.&lt;br /&gt;
By adding one to our growing tower we're ready to meet our first actual &lt;em&gt;test fixture&lt;/em&gt; enjoying the power of:&lt;/p&gt;
&lt;h2&gt;[Inject(string)]&lt;/h2&gt;
&lt;p&gt;To enjoy the benefits of our stored service provider reference, we must expose an instance method on our &amp;quot;scoped&amp;quot; test fixture that accepts services. We could've used constructor injection, but that's already &amp;quot;in use&amp;quot; by NUnit &lt;code&gt;[TestFixture(args)]&lt;/code&gt; functionality. Once you start composing tests like this package allows, you can get &lt;em&gt;much more value&lt;/em&gt; from things like that. So a void method will have to do. A fresh &amp;quot;standalone&amp;quot; and &amp;quot;scoped&amp;quot; test fixture will look like this:&lt;/p&gt;
&lt;p&gt;using Same.Namespace.As.SetupFixture;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Inject(nameof(Inject))]
public class LookMaImFreeAsABird
{
    IDataTypeService dataTypeService = null!;

    public void Inject(IDataTypeService dataTypeService)
    {
        this.dataTypeService = dataTypeService;
    }

    [Test]
    public void FiddleWithDataTypeA()
    {
        // ...
    }

    [Test]
    public void CreateDataTypeB()
    {
        // ...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice the beauty of &lt;em&gt;no forced ctors&lt;/em&gt;, &lt;em&gt;no base class&lt;/em&gt; and &lt;em&gt;no overrides&lt;/em&gt; in that class! Not to mention, you can have &lt;em&gt;several&lt;/em&gt; of those!&lt;/p&gt;
&lt;h2&gt;Interlude: Transactions&lt;/h2&gt;
&lt;p&gt;With the above setup the individual fixtures are free to create &lt;code&gt;ICoreScope&lt;/code&gt; instances from Umbraco and commit or dispose them as you wish. Just writing three sentences about it here doesn't really give the method justice. Suffice to say, just give it a go!&lt;br /&gt;
However it won't work when we use &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt;. There's no way to spread a core scope across threads, and there's not even a way to spread gool old .NET transaction scopes across. I guess you could go full old school and bring DCOM into the picture, but after a lot of failed attempts I finally stumbled over an obvious solution.&lt;/p&gt;
&lt;h2&gt;Snapshots&lt;/h2&gt;
&lt;p&gt;The final itch has taken me the longest, and even longer to stuff into an attribute rather than yet another base class. I must admit it took a desperate (but accurate) final plea with ChatGPT 5.1 to see the obvious solution just lying there to implement. All database engines, or at least the two I've implemented, support some sort of fast backup. &lt;code&gt;VACUUM INTO&lt;/code&gt; in SQLite and &lt;code&gt;CREATE/RESTORE DATABASE AS SNAPSHOT&lt;/code&gt; in SQL Server.&lt;/p&gt;
&lt;p&gt;I had two intermediate base classes for a few weeks, but this last weekend I ran over the goal line:&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;[ReusableDatabase(type, string)]&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;If you configure &lt;code&gt;Tests:Database:DatabaseType&lt;/code&gt; in your &lt;code&gt;appSettings.Tests.Local.json&lt;/code&gt; and set any of the non-none values in the &lt;code&gt;[UmbracoTest]&lt;/code&gt; database parameter, you can also add &lt;code&gt;[ReusableDatabase(typeof(SeedClass), nameof(SeedClass.Configure))]&lt;/code&gt; to get a new type of &lt;code&gt;ITestDatabase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As of writing it requires a method to be implemented in the setup fixture, or on some supporting type. Its mission is to configure whether the database needs a fresh seed and how to seed the initial data for all the tests. Only if we say so, the database is installed and re-seeded. For all other scopes it's just restored from that initial snapshot.&lt;/p&gt;
&lt;p&gt;The seeding can be done in any way you please. My favorite is importing things using uSync, and that might just become another blog post. For simplicity let's say we're testing variants of property editors based on a datatype we want all tests to start with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UmbracoTest(
    Database = UmbracoTestOptions.Database.NewSchemaPerTest,
    Boot = true,
    Logger = UmbracoTestOptions.Logger.Console
)]
[ExtendableSetUpFixture]
[OneTimeUmbracoSetUp]
[ServiceProvider]
[ReusableDatabase(nameof(ConfigureSeeding))]
public class ReusedDbAttributeSetUp : UmbracoIntegrationTest
{
    public static void ConfigureSeeding(ReusableTestDatabaseOptions options)
    {
        options.NeedsNewSeed = _ =&amp;gt; Task.FromResult(true);
        options.SeedData = async (services) =&amp;gt;
        {
            await TestContext.Progress.WriteLineAsync(&amp;quot;Creating datatype&amp;quot;);
            await services.GetRequiredService&amp;lt;IDataTypeService&amp;gt;().CreateAsync(
                new DataType
                (
                    new TextboxPropertyEditor
                    (
                        services.GetRequiredService&amp;lt;IDataValueEditorFactory&amp;gt;(),
                        services.GetRequiredService&amp;lt;IIOHelper&amp;gt;()
                    ),
                    services.GetRequiredService&amp;lt;IConfigurationEditorJsonSerializer&amp;gt;()
                )
                {
                    Name = &amp;quot;A seeded textbox&amp;quot;
                },
                Umbraco.Cms.Core.Constants.Security.SuperUserKey
            );
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The method has to be static void. If it's on the setup fixture you can omit the type from the attribute parameters.&lt;br /&gt;
Now all tests within this &amp;quot;scope&amp;quot; will have access to the seeded textbox. Such seeding code might quickly grow out of hand though, and that's why I prefer just importing the content schema from the web project in the same repo as my tests.&lt;/p&gt;
&lt;h2&gt;Which ones to choose&lt;/h2&gt;
&lt;p&gt;As you've hopefully realized by now you can introduce really slim intermediate base classes that set up the initial environment for a bunch of use-cases and scenarios. Leaving your actual test fixtures free to be composed just as you wish, and with all the features of NUnit at your disposal.&lt;/p&gt;
&lt;p&gt;I'm sure you can see that the last setup fixture example above makes for a nice base class to avoid repeating that tower of attributes. The &lt;a href="https://github.com/lars-erik/NUnitCompositionWithUmbraco/tree/main/UmbracoTestsComposition"&gt;repository has a few examples using a few or all of the attributes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The final trick I haven't disclosed above is how to do a &amp;quot;mid-fixture&amp;quot; rollback. The reusable database implementations have a &amp;quot;RestoreSnapshot&amp;quot; method, so in a &lt;code&gt;[TearDown]&lt;/code&gt; you can go:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;await serviceProvider.GetRequiredService&amp;lt;IReusableDatabase&amp;gt;().RestoreSnapshot();&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;That makes it so that whatever test comes next it's unaffected by the changes you've made. This is of course what happens during &lt;code&gt;[OneTimeSetUp]&lt;/code&gt; for any setup fixture using &lt;code&gt;[ReusableDatabase]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want to try this out, I recommend going with &lt;code&gt;[ReusableDatabase]&lt;/code&gt; (and uSync) for everything that use more than 10ish artifacts like data and content types, not to mention content. Whenever you want to run changes through the Management API, or definitely if you want to test how all your sites' elements look in the Delivery API. It's a no-brainer when you go full integration with &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt; and more than one HTTP call.&lt;/p&gt;
&lt;p&gt;If all your tests have all they need in a fresh Umbraco database, but they all mutate it so you need cleanup, it'll be blazing fast if you can use &lt;code&gt;ICoreScope&lt;/code&gt; with autocommit off. As long as you don't need to test via HTTP endpoints, this is a better option than restoring the snapshot. Using a snapshot restore between fixtures however is still a nice option to keep around, so I still opt for &lt;code&gt;[ReusableDatabase]&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Want more?&lt;/h2&gt;
&lt;p&gt;I'm definitely going to be in &amp;quot;only fix what breaks for me&amp;quot; mode for a little while, as this was just gonna be a hacktoberfest weekend project. Turned out to take too much of my spare time for one and a half month instead.&lt;/p&gt;
&lt;p&gt;But I honestly believe this'll save some trees if applied well to CI pipelines running all day long.&lt;br /&gt;
And I've gone from 90 sec to 26 sec to execute a full test suite, a lot of which would run for &lt;em&gt;any&lt;/em&gt; filter.&lt;/p&gt;
&lt;p&gt;The package is currently listed as a beta (pre-release) on nuget and if it doesn't crash much I might just promote it to full visibility. It's a bit furry on the edges and has a bit of legacy to it (already), but if you stick the namespaces in the project file and leave the stray base classes alone I think you'll be good.&lt;/p&gt;
&lt;p&gt;All this is to say I'd love for conversation about what it solves and if it could do it better. I'd love even more to throw out a bit of the code because Umbraco suddenly fixed the core two issues. Let me hear from you if you try it out. Feel free to clone the code and mess about, although I reserve the right to refactor the mess myself that beautiful day I get to keep going with this. &lt;/p&gt;
&lt;p&gt;Looking forward to hearing how (and if) you like it. Hope you have a go!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/lars-erik/NUnitCompositionWithUmbraco"&gt;Source repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Umbraco.Community.Integration.Tests.Extensions"&gt;Nuget package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Umbraco.Cms.Tests.Integration/"&gt;Umbraco Cms Tests Integration package&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      <pubDate>Tue, 25 Nov 2025 07:11:08 Z</pubDate>
      <a10:updated>2025-11-25T07:11:08Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1139</guid>
      <link>https://blog.aabech.no/archive/environmental-approvaltests/</link>
      <category>unit testing</category>
      <title>Environmental ApprovalTests</title>
      <description>&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;A while ago I wrote a &lt;a href="//blog.aabech.no/archive/exploiting-approvaltests-for-clearer-tests/"&gt;post about a tool called ApprovalTests&lt;/a&gt;. I've included it in my workshop on unit testing Umbraco, and people are amazed at its usefulness. Having Visual Studio pop a diff in your face when stuff breaks is a real timesaver. However, when I ran the workshop at CodeGarden 18, I realized people were concerned that their tests would be impossible to run in CI environments and the like. Not to worry - ApprovalTests have you covered. (Pun intended)&lt;/p&gt;
&lt;h2&gt;Environmentalism&lt;/h2&gt;
&lt;p&gt;When declaring reporters with ApprovalTests, you can specify multiple reporters. That's not all. The reporters have an extensive API on them, which caters for us tailoring everything. There is one particularly interesting interface on all &amp;quot;diff-reporters&amp;quot; named &lt;code&gt;IEnvironmentAwareReporter&lt;/code&gt;.&lt;br /&gt;
The &lt;code&gt;VisualStudioReporter&lt;/code&gt; one has a nice little one-liner implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public override bool IsWorkingInThisEnvironment(string forFile)
{
    return OsUtils.IsWindowsOs() &amp;amp;&amp;amp; base.IsWorkingInThisEnvironment(forFile) &amp;amp;&amp;amp; LaunchedFromVisualStudio();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The last function call there checks if the current process is a descendent of &lt;code&gt;devenv.exe&lt;/code&gt;. If it isn't, execution will just be passed to the next reporter in the chain. So there! It won't break your CI build.&lt;/p&gt;
&lt;p&gt;But what do we want in our CI build, then? Probably a regular WhateverUnit assertion. I use NUnit, so that'll be our example.&lt;/p&gt;
&lt;h2&gt;Falling back&lt;/h2&gt;
&lt;p&gt;Take this little test. I approved the result for seed 1, and we'll examine the output for an invalid result by swapping to 2:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[TestFixture]
[UseReporter(typeof(VisualStudioReporter))]
public class When_Running_In_Different_Environments
{
    [Test]
    public void Delegates_To_Most_Appropriate_Reporter()
    {
        var rnd = new Random(1);
        var items = Enumerable
            .Range(0, 10)
            .Select(x =&amp;gt; rnd.Next());
        Approvals.VerifyAll(items, &amp;quot;&amp;quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's change the seed to 2 to fail the test:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var rnd = new Random(2);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if we run the test with NUnit3-Console.exe, we'll get an exception saying that ApprovalTests can't find Visual Studio:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nunit3-console.exe .\bin\debug\environmentaltests.dll

...
1) Error : EnvironmentalTests.When_Running_In_Different_Environments.Delegates_To_Most_Appropriate_Reporter
System.Exception : Couldn't find Visual Studio at
at ApprovalTests.Reporters.GenericDiffReporter.Report(String approved, String received) in C:\code\ApprovalTests.Net\ApprovalTests\Reporters\GenericDiffReporter.cs:line 142
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It sounds worse than it is. ApprovalTests insists that it has &lt;em&gt;something&lt;/em&gt; to do. We can add a reporter to the fixture to fix it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[TestFixture]
[UseReporter(typeof(VisualStudioReporter), typeof(NUnitReporter))]
public class When_Running_In_Different_Environments
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now when we run the test, we get a pure assertion failure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1) Failed : EnvironmentalTests.When_Running_In_Different_Environments.Delegates_To_Most_Appropriate_Reporter
Expected string length 165 but was 162. Strings differ at index 6.
Expected: &amp;quot;[0] = 534011718\n[1] = 237820880\n[2] = 1002897798\n[3] = 165700...&amp;quot;
But was:  &amp;quot;[0] = 1655911537\n[1] = 867932563\n[2] = 356479430\n[3] = 211537...&amp;quot;
-----------------^
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice it didn't even mention Visual Studio. Going back into our favorite IDE will start popping diffs again, and the NUnit one will govern the output.&lt;/p&gt;
&lt;h2&gt;Cleaning up&lt;/h2&gt;
&lt;p&gt;So should we go around declaring at least two reporters on all our fixtures, then? Luckily not. There are two more tricks that are nice to know.&lt;/p&gt;
&lt;p&gt;First, the reporter attribute is found by iterating up the inheritance hierarchy. It can be defined as high up as all your &lt;code&gt;[assembly:XAttribute]&lt;/code&gt; metadata. You can create a file in your test project root called &lt;code&gt;ApprovalsConfig.cs&lt;/code&gt; for instance. Within it, you declare your reporters on the assembly level:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using ApprovalTests.Reporters;

[assembly:UseReporter(typeof(VisualStudioReporter), typeof(NUnitReporter))]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The second is that you might not want the NUnit assertion when you run in VS (for some reason), or maybe some other tool might be in your way. You might even want composite reporters. In any case, it also makes for a bit nicer setup if you implement the &lt;code&gt;FirstWorkingReporter&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class EnvironmentReporter : FirstWorkingReporter
{
    public static readonly EnvironmentReporter INSTANCE = new EnvironmentReporter();

    public EnvironmentReporter()
        : base(
            VisualStudioReporter.INSTANCE,
            NUnitReporter.INSTANCE
        )
    {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With it, we can change our &lt;code&gt;UseReporter&lt;/code&gt; to be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[assembly:UseReporter(typeof(EnvironmentReporter))]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now the first reporter to confirm its environment is executed, and the rest are ignored. You might want to keep the NUnit one around, though. In that case, you can implement &lt;code&gt;MultiReporter&lt;/code&gt; in the same way - which coincidentally is the same that &lt;code&gt;UseReporterAttribute&lt;/code&gt; does.&lt;/p&gt;
&lt;p&gt;I encourage you to go have a look at &lt;a href="https://github.com/approvals/ApprovalTests.Net/tree/master/ApprovalTests/Reporters"&gt;all the built-in reporters&lt;/a&gt; and get some inspiration for even more helpful reporting.&lt;/p&gt;
&lt;p&gt;I'd rejoice for any cool usages in the discussion thread. :)&lt;/p&gt;
</description>
      <pubDate>Sun, 03 Jun 2018 21:24:46 Z</pubDate>
      <a10:updated>2018-06-03T21:24:46Z</a10:updated>
    </item>
  </channel>
</rss>