Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Test window should group by inner classes when grouping by namespace is enabled.
Magnus Lidbom
#1 Posted : Sunday, December 8, 2024 1:52:30 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 8/30/2012(UTC)
Posts: 43

Thanks: 7 times
Was thanked: 7 time(s) in 7 post(s)
Note that this is how the Rider and Resharper test UI's do it by default.
The below code is a simple real world example of why I really need this feature.
In practice, the nesting often gets much deeper than in this simple example, and the full test name without nesting may not even fit within the tests window on my monitor!
But even without that, compare trying to read these two:

What NCrunch does:
Code:

Assertion_library_specification+StringAssertion_method+NotNull_throws_for
    null_string
Assertion_library_specification+StringAssertion_method+NotNullEmptyOrWhitespace_throws_for_
    null_string
    null_string
    empty_string
    spaces_string
    tabs_string
    newLine_string


What I want, and what Rider and ReSharper does:
Code:

Assertion_library_specification
    StringAssertion_method
        NotNull_throws_for
            null_string
        NotNullEmptyOrWhitespace_throws_for_
            null_string
            empty_string
            spaces_string
            tabs_string
            newLine_string


Imagine that difference multiplied by hundreds of tests....

The code example:
(Note: The XFactAtttribute changes the behaviour of XUnit such that the test is only executed for the class in which it is defined, not for inheriting classes. I also have an XTestAttribute that does the same for NUnit.)
Code:

using System;
using Compze.Testing.TestFrameworkExtensions.XUnit;

namespace Compze.Tests.Unit.Internals.Contracts;

public class Assertion_library_specification : AssertionMethodsTest
{
   public class StringAssertion_method : Assertion_library_specification
   {
      const string EmptyString = "";
      static readonly string? NullString = null;
      const string SpacesString = " ";
      const string TabsString = "   ";
      static readonly string NewLineString = Environment.NewLine;

      public class NotNull_throws_for : StringAssertion_method
      {
         [XFact] public void null_string() => ThrowsAndCapturesArgumentExpressionText(() => Asserter.NotNullOrEmpty(NullString), NullString);
      }

      public class NotNullEmptyOrWhitespace_throws_for_ : StringAssertion_method
      {
         [XFact] public void null_string() => ThrowsAndCapturesArgumentExpressionText(() => Asserter.NotNullEmptyOrWhitespace(NullString), NullString);
         [XFact] public void empty_string() => ThrowsAndCapturesArgumentExpressionText(() => Asserter.NotNullEmptyOrWhitespace(EmptyString), EmptyString);
         [XFact] public void spaces_string() => ThrowsAndCapturesArgumentExpressionText(() => Asserter.NotNullEmptyOrWhitespace(SpacesString), SpacesString);
         [XFact] public void tabs_string() => ThrowsAndCapturesArgumentExpressionText(() => Asserter.NotNullEmptyOrWhitespace(TabsString), TabsString);
         [XFact] public void newLine_string() => ThrowsAndCapturesArgumentExpressionText(() => Asserter.NotNullEmptyOrWhitespace(NewLineString), NewLineString);
      }
   }
}

Magnus Lidbom
#2 Posted : Sunday, December 8, 2024 2:16:32 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 8/30/2012(UTC)
Posts: 43

Thanks: 7 times
Was thanked: 7 time(s) in 7 post(s)
Just in case someone sees that test structure, likes it as much as I do and want to use it, the attributes that makes it work in practice are pretty simple and you can find the code here: XUnit, NUnit
Magnus Lidbom
#3 Posted : Sunday, December 8, 2024 6:14:20 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 8/30/2012(UTC)
Posts: 43

Thanks: 7 times
Was thanked: 7 time(s) in 7 post(s)
I've been refactoring a legacy test class with a few huge test methods into this structure and I'm actually a bit giddy about just how much better the code is.
The below test file really makes me smile remembering how the old monolith looked. it turns out that it was hiding more than 200 assertions!

Anyway. This test class is displayed in NCrunch as.

Code:

Composite_aggregate_specification+After_constructing_root_aggregate_with_name_root_and_slaving_a_query_model_to_the_aggregates_events+After_calling_AddEntity_with_name_RootEntity_and_a_new_Guid+Using_RootEntity+After_calling_AddEntity_with_name_entity1_and_a_newGuid+After_calling_AddEntity_with_name_entity2_and_a_newGuid+After_calling_rename_on_entity1_with_string_newName+After_calling_rename_on_entity2_with_string_newName2


Even on my 4K monitor, the line does not fit on the screen. And most of that enormous string is repeated again and again for other parts of the Composite_aggregate_specification.
You can probably see why I would want this instead:
Code:

Composite_aggregate_specification
   After_constructing_root_aggregate_with_name_root_and_slaving_a_query_model_to_the_aggregates_events
      After_calling_AddEntity_with_name_RootEntity_and_a_new_Guid
        Using_RootEntity
           After_calling_AddEntity_with_name_entity1_and_a_newGuid
              After_calling_AddEntity_with_name_entity2_and_a_newGuid
                 After_calling_rename_on_entity1_with_string_newName
                    After_calling_rename_on_entity2_with_string_newName2

Here's the actual test code:
Code:

using Compze.Testing.TestFrameworkExtensions.XUnit;
using FluentAssertions;

namespace Compze.Tests.Unit.CQRS.Aggregates.NestedEntitiesTests.GuidId;

public static partial class Composite_aggregate_specification
{
   public partial class After_constructing_root_aggregate_with_name_root_and_slaving_a_query_model_to_the_aggregates_events
   {
      public partial class After_calling_AddEntity_with_name_RootEntity_and_a_new_Guid
      {
         public partial class Using_RootEntity
         {
            public partial class After_calling_AddEntity_with_name_entity1_and_a_newGuid
            {
               public partial class After_calling_AddEntity_with_name_entity2_and_a_newGuid
               {
                  public partial class After_calling_rename_on_entity1_with_string_newName
                  {
                     public class After_calling_rename_on_entity2_with_string_newName2 : After_calling_rename_on_entity1_with_string_newName
                     {
                        public After_calling_rename_on_entity2_with_string_newName2() => _entity2.Rename("newName2");

                        [XFact] public void entity2_name_is_newName2() => _entity2.Name.Should().Be("newName2");
                        [XFact] public void entity2_QueryModel_name_is_newName2() => _qmEntity2.Name.Should().Be("newName2");
                        [XFact] public void entity1_name_remains_newName() => _entity1.Name.Should().Be("newName");
                        [XFact] public void entity1_QueryModel_name_remains_newName() => _qmEntity1.Name.Should().Be("newName");
                     }
                  }
               }
            }
         }
      }
   }
}
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

YAF | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.027 seconds.
Trial NCrunch
Take NCrunch for a spin
Do your fingers a favour and supercharge your testing workflow
Free Download