3

I'm using MSTest and I want to write log entry before test executes and after it finishes. Obviously I don't want to add custom logging code at the beginning and end of each test - it would only make the test unreadable and seemed like a lot of effort (I have > 500 tests)

Using TestInitialize and TestCleanup seemed like the way to go but I can't get the test name.

Does anyone knows how to do this?

Dror Helper
  • 30,292
  • 15
  • 80
  • 129
  • and why do you need the test name ? If you can tell us what you're trying to achieve using logging, maybe i could give a better answer. – Gishu Oct 07 '10 at 08:32
  • @Gishu - I have a long log file from all of the tests and I want to see in that log what test the current entry belong to. By adding logging before and after each test I can "bound" the test's information – Dror Helper Oct 07 '10 at 09:17

3 Answers3

3

In MSTest, the name of the test case is available in the test context property. So to access it in the test initialize (as well as test cleanup) method, you can use something like this: -

    [TestInitialize()]
    public void MyTestInitialize() 
    {
        if (string.Equals(**TestContext.TestName**, "TestMethod1", StringComparison.OrdinalIgnoreCase))
        { 
        }
    }
Giulio Vian
  • 8,248
  • 2
  • 33
  • 41
Aseem Bansal
  • 799
  • 4
  • 14
2

We use nLog for logging and an base class for test initialize and test cleanup that logs if a test has passed or not.

This is the base class:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using NLog;

namespace Tests
{
    public class TestBase
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        public TestContext TestContext { get; set; }

        [TestCleanup]
        public void TestCleanup()
        {
            string testName = string.Format("{0}.{1}", TestContext.FullyQualifiedTestClassName, TestContext.TestName);
            UnitTestOutcome currentTestOutcome = TestContext.CurrentTestOutcome;
            string message = string.Format("Test '{0}' {1}", testName, currentTestOutcome.ToString().ToUpperInvariant());
            if (currentTestOutcome != UnitTestOutcome.Passed)
            {
                Logger.Error(message);
            }
            else
            {
                Logger.Info(message);
            }
        }

        [TestInitialize]
        public void TestInitialize()
        {
            string testName = string.Format("{0}.{1}", TestContext.FullyQualifiedTestClassName, TestContext.TestName);
            Logger.Info("Started with test '{0}'", testName);
        }
    }
}

And here is the use of it

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Tests
{
    [TestClass]
    public class JustTest : TestBase
    {
        [TestMethod]
        public void Fail()
        {
            Assert.IsTrue(false);
        }

        [TestMethod]
        public void Pass()
        {
            Assert.IsTrue(true);
        }
    }
}

here is the part from log file

Started with test 'Tests.JustTest.Fail'
Test 'Tests.JustTest.Fail' FAILED

Started with test 'Tests.JustTest.Pass'
Test 'Tests.JustTest.Pass' PASSED
0

Update: Ok now I see what you're getting at. Bad news is I don't use MSTest or a MSTest fixture to find out..

In NUnit, you could

>"nunit-console.exe" API_Tests.dll /out:My.log /labels

THis outputs the following log file

***** Test.Gumba.API_Tests.Tests.ArithmeticProgression.DummyTest2
Woohoo! made it till test2
***** Test.Gumba.API_Tests.Tests.ArithmeticProgression.GeneratesTheRightProgressionAsSpecifiedByTheUser
Try#0 failed. due to 0. Retrying NUnit.Framework.AssertionException:   Expected is <System.Int32[10]>, actual is <System.Int32[0]>
<snipped>...

I was looking at the command line switches for MSTest and the following looks interesting

mstest /testcontainer:Some.dll /detail:testname

--------------- previous answer follows -----
To answer your question to the point, 'Execute around' methods can be done using a method that takes a delegate. However if you could elaborate on why you need this, maybe there is a better solution to achieve whatever it is you're after

e.g.

private void LogAround(Action action)
{
  // log entry with calling method name using StackTrace class
  action();
  // log exit
}

and calls would be

Do( delegate {
  // test code
});
Gishu
  • 134,492
  • 47
  • 225
  • 308
  • unfortunately that means that I would need to add this code to all of may present and future tests hurting their readability. I would also need to make sure all of the devs on the team use this in all their tests... I want a solution that "aromatically" adds logging to all of my tests – Dror Helper Oct 07 '10 at 09:12