How to provide force isolation testing in MSpec when static elements / methods are required?

Ok I am trying to wrap my head around why MSpec uses static methods / variables. (Well, not exactly static methods, but with delegates of member variables, it's pretty much the same).

This makes reuse of contexts impossible. Either go through this and make sure that all static variables are reset manually. This does not require forced isolation. If one test sets some variables, and the next tests it, it will pass when it is not.

It starts to get very annoying. What I do in one β€œbecause” should just stay there, and not be carried over to all other random tests just because they use the same context.

Edit -

The question is how to isolate the ENFORCE test insulation. For example, view the specs below, dividing FooContext . Let's take a wild guess if should_not_throw pass?

 public class FooContext { Establish context = () => Subject = new Foo(); public static Foo Subject; public static int result; public static Exception ex; } public class When_getting_an_int_incorrectly : FooContext { Because of = () => ex = Exception.Catch(() => result = Subject.GetInt(null)); It should_throw = () => ex.ShouldNotBeNull(); } public class When_getting_an_int_correctly : FooContext { Because of = () => ex = Exception.Catch(() => result = Subject.GetInt(0)); It should_not_throw = () => ex.ShouldBeNull(); } 
+4
source share
2 answers

This is a technical and historical limitation.

  • You need statistics fields to share information between delegates (Install, Therefore, This, Clear).
  • MSpec is trying to mimic rspec, so I think Aaron thinks that delegates are well suited and have released the syntax you see today in 2008 or 2009. This syntax still exists today.

Regarding context / context sharing classes: from what you are declaring, it looks like you are abusing the concept. You should always initialize static fields in Setup, so the global state will become inappropriate. Contextual exchange should be well considered, therefore, to quote you, this does not happen by chance. Try using helper methods for complex setup and be more detailed (I would say explicit) in the settings. This will help make your specifications more readable.

+2
source

Here it is. I would like to introduce my (partial) solution to the problem (Ensuring the isolation of devices and settings). This is a solution to the problem of the plumbing code at the same time.

I basically put the tire container in the instrument instance and make sure that the device is recreated for each individual specification. If any other setting is required, simply inherit or add to the instrument.

(Note that this uses a structural map and a map / moq / automocking container structure. I am sure this is the same for different containers / mocking framework.)

 /// <summary> /// This is a base class for all the specs. Note this spec is NOT thread safe. (But then /// I don't see MSpec running parallel tests anyway) /// </summary> /// <typeparam name="T"></typeparam> /// <remarks> /// This class provides setup of a fixture which contains a) access to class under test /// b) an auto mocking container and c) enforce a clean fixture for every spec. /// </remarks> public abstract class BaseSpec<T> where T : class { public static TestFixture Fixture; private Establish a_new_context = () => { Fixture = new TestFixture(); MockedTypes = new Dictionary<Type, Action>(); }; /// <summary> /// This dictionary holds a list of mocks that need to be verified by the behavior. /// </summary> private static Dictionary<Type, Action> MockedTypes; /// <summary> /// Gets the mock of a requested type, and it creates a verify method that is used /// in the "AllMocksVerified" behavior. /// </summary> /// <typeparam name="TMock"></typeparam> /// <returns></returns> public static Mock<TMock> GetMock<TMock>() where TMock : class { var mock = Mock.Get(Fixture.Context.Get<TMock>()); if (!MockedTypes.ContainsKey(typeof(TMock))) MockedTypes.Add(typeof(TMock), mock.VerifyAll); return mock; } [Behaviors] public class AllMocksVerified { private Machine.Specifications.It should_verify_all = () => { foreach (var mockedType in MockedTypes) { mockedType.Value(); } }; } public class TestFixture { public MoqAutoMocker<T> Context { get; private set; } public T TestTarget { get { return Context.ClassUnderTest; } } public TestFixture() { Context = new MoqAutoMocker<T>(); } } } 

And here is an example of use.

  public class get_existing_goo : BaseSpec<ClassToTest> { private static readonly Goo Param = new Goo(); private Establish goo_exist = () => GetMock<Foo>() .Setup(a => a.MockMethod()) .Returns(Param); private static Goo result; private Because goo_is_retrieved = () => result = Fixture.Context.ClassUnderTest.MethodToTest(); private It should_not_be_null = () => result.ShouldEqual(Param); } 

In principle, if something needs to be exchanged, put it in a copy of the device itself. This "forces" separation ... something.

I still prefer Xunit in this regard.

+1
source

Source: https://habr.com/ru/post/1496075/


All Articles