SubSpec - Observation

Topics: ReSharper test runner
Sep 3, 2013 at 7:42 AM
Hello!

I have problems with test results from Subspecs's Observation methods - sentences are incorrectly merged (but Assert methods' results are OK).
Coordinator
Sep 3, 2013 at 7:58 AM
Hi. Could you provide a little more detail? What do you mean by merged? And do you have a solution that reproduces the issue?
Sep 3, 2013 at 8:42 AM
Edited Sep 3, 2013 at 8:48 AM
Hi,
thanks for fast response. I mean concatenated.

Here's a dummy example:
        [Specification]
        public void Update()
        {
            var testString = default(string);

            "Given an empty string"
                .Context(() => testString = "");

            "when an action performed"
                .Do(() => testString = "test");

            "it should set its value"
                .Observation(() => Assert.NotEqual("", testString));

            "it should set its value correctly "
                .Observation(() => Assert.Equal("test", testString));
        }
And a screenshot of result in Resharper's Unit Test Sessions:
http://img42.com/JcY0J
  • - it should set its value
  • - it should set its value correctly
  • { Given an empty string when an action performed
  • } Given an empty string when an action performed
BTW: I am using Xunit v2.0.50727 and Subspec (obtained from NuGet).
Sep 3, 2013 at 9:10 AM
I've checked SubSpec's source code - it's just the awkward way of creating observation sentences. Sorting is Resharper's issue, but that's the default sort order. I'll have to modify SubSpec obviously.
Coordinator
Sep 3, 2013 at 9:02 PM
Yeah, ReSharper re-orders alphabetically for readability - they're still run in the appropriate order, though. This would have to be a change for SubSpec. I guess it's implementing Context, Do and Observation as Theories. It might be better if just Observations were Theories, and the Context + Do names were made part of the Specification's DisplayName, although the runner won't necessarily display that correctly, either. Normally, the node in the tree has the method name, and any theories are child nodes with the correct display name. If a Fact has a display name, it's displayed as a child of the method - like a Theory. So it still might not print as prettily as you'd like.
Sep 4, 2013 at 6:34 AM
Edited Sep 4, 2013 at 3:05 PM
Quick hack in Subspec source - to get sentences with preceding "--" for observations. E.g.:
-- Given an empty string when an action performed, it should set its value
-- Given an empty string when an action performed, it should set its value correctly

Redundant tests for observations are with this solution no more shown in Resharper's Unit Test Sessions Window.
public IEnumerable<ITestCommand> ObservationCommands(string name, IMethodInfo method)
            {
                if (_observations.Count() == 0)
                    yield break;

                bool setupExceptionOccurred = false;
                IDisposable systemUnderTest = default(IDisposable);

                Action setupAction = () =>
                {
                    try
                    {
                        systemUnderTest = SpecificationPrimitiveExecutor.Execute(_context);

                        if (_do != null)
                            SpecificationPrimitiveExecutor.Execute(_do);
                    }
                    catch (Exception)
                    {
                        setupExceptionOccurred = true;
                        throw;
                    }
                };

                //yield return new ActionTestCommand(method, "{ " + name, 0, setupAction);
                setupAction();

                foreach (var observation in _observations)
                {
                    // do not capture the iteration variable because 
                    // all tests would point to the same observation
                    var capturableObservation = observation;
                    Action perform = () =>
                    {
                        if (setupExceptionOccurred)
                            throw new ContextSetupFailedException("Setting up Context failed");

                        SpecificationPrimitiveExecutor.Execute(capturableObservation);
                    };
                    var testDescription = String.Format("-- {0}, {1}", name, capturableObservation.Message);
                    yield return new ActionTestCommand(method, testDescription, 0, perform);
                }

                Action tearDownAction = () =>
                {
                    if (systemUnderTest != null)
                        systemUnderTest.Dispose();

                    if (setupExceptionOccurred)
                        throw new ContextSetupFailedException("Setting up Context failed, but Fixtures were disposed.");
                };

                //yield return new ActionTestCommand(method, "} " + name, 0, tearDownAction);
                tearDownAction();
            }