3

I am using selenium webdriver in visual studio Using NUNIT. The code of test case is

I want to Log that test case is passed or fail in a variable right after the test case is executed.How can I achieve that?

Mehwish
  • 55
  • 9

2 Answers2

3

NUnit

Assume you use NUnit (because what's in the question looks like MSTest), you could write custom IWrapTestMethod attribute to extend the test command. The attribute gives you an opportunity to inspect on the test and test result before and after each test run:

// I don't know where your variable is, so just use this dummy class with
// some dummy static properties.
class TestResultKeeper
{
    public static TestResult TestResult { get; set; }
    public static ResultState ResultState => TestResult?.ResultState ?? ResultState.Failure;
    public static bool IsPassed => ResultState == ResultState.Success;
    public static Exception Exception { get; set; }
}

// Custom NUnit 3 attribute to extend test method
public class LogTestAttribute : Attribute, IWrapTestMethod
{
    public TestCommand Wrap(TestCommand command)
    {
        // Wrap test command
        return new LogTestResultCommand(command);
    }
}

class LogTestResultCommand : DelegatingTestCommand
{
    public LogTestResultCommand(TestCommand innerCommand)
        : base(innerCommand)
    {

    }

    public override TestResult Execute(TestExecutionContext context)
    {
        try
        {
            var result = innerCommand.Execute(context);

            // Set test result to TestResultKeeper

            TestResultKeeper.TestResult = result;
            TestResultKeeper.Exception = null;

            return result;
        }
        catch (Exception e)
        {
            // Exception thrown from test. Test failed.

            TestResultKeeper.TestResult = null;
            TestResultKeeper.Exception = e.InnerException;
            throw;
        }
    }
}

Usage:

[Test, LogTest]
public void Test1()
{
    Assert.Fail();
}

[Test, LogTest]
public void Test2()
{
    Assert.Pass();
}

MSTest

Assume your test is written in MSTest (as per your example), you could create a new test method attribute and derive from TestMethodAttribute, and do similar things as above:

class TestResultKeeper
{
    public static TestResult TestResult { get; set; }
    public static UnitTestOutcome TestOutcome => TestResult?.Outcome ?? UnitTestOutcome.Failed;
    public static bool IsPassed => TestOutcome == UnitTestOutcome.Passed;
    public static Exception Exception { get; set; }
}

public class LogTestTestMethodAttribute : TestMethodAttribute
{
    public override TestResult[] Execute(ITestMethod testMethod)
    {
        var testResult = base.Execute(testMethod)[0];


        TestResultKeeper.TestResult = testResult;
        TestResultKeeper.Exception = testResult.TestFailureException;

        return new[] { testResult };
    }
}

Usage:

[LogTestTestMethod]
public void TestMethod1()
{
}
Community
  • 1
  • 1
weichch
  • 9,306
  • 1
  • 13
  • 25
  • @Amna I created a dummy `TestResultKeeper` because I don't know where you'd like to save test result. You can change it to somewhere else. – weichch Mar 24 '20 at 19:23
  • could you please update MStest as well just like you did in Nunit? – Mehwish Mar 25 '20 at 11:03
  • @Amna MSTest example is already in the answer. See the `MSTest` title. – weichch Mar 25 '20 at 19:21
  • In `MStest` it is mentioned do similar things as above. I want to know which things? @weichch – Mehwish Mar 26 '20 at 05:03
  • @Amna Oh, by that I just meant "using your own types to extend the test framework". As you can see in the example in MSTest section, I used `LogTestTestMethodAttribute` which is derived from `TestMethodAttribute`, and `LogTestTestMethodAttribute` is similar to `LogTestAttribute` in NUnit. The example should already work. – weichch Mar 26 '20 at 05:17
  • Using Mstest code showing some exception like 1) `public static UnitTestOutcome TestOutcome => TestResult?.Outcome ?? UnitTestOutcome.Failed`; **Exception : "Operator '??' cannot be applied to operands of type 'TestOutcome?' and 'UnitTestOutcome** 2) `public override TestResult[] Execute(ITestMethod testMethod)` Exception : **LogTestTestMethod.Execute(ITestMethod)': no suitable method found to override** – Mehwish Mar 26 '20 at 08:31
  • 3) `var testResult = base.Execute(testMethod)[0];` exception : **Attribute' does not contain a definition for 'Execute** 4) `return new[] { testResult }`; Exception : **Cannot implicitly convert type '?[]' to 'Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult[]** – Mehwish Mar 26 '20 at 08:32
  • 5) `public class LogTestTestMethod : TestMethodAttribute` Exception : **LogTestTestMethod': cannot derive from sealed type 'TestMethodAttribute** – Mehwish Mar 26 '20 at 09:11
  • @Amna Looks like you are using MSTest v1, and my code is MSTest v2. MSTest V1 has been discontinued, and not able to extend easily. Given MSTest v2 offers more (including extendability), I'd suggest you move to v2. It would be a trivial change https://devblogs.microsoft.com/devops/upgrade-to-mstest-v2/. – weichch Mar 26 '20 at 09:36
  • No, I am using MStest v2.1.0. – Mehwish Mar 26 '20 at 09:52
  • As per the source code of `TestMethodAttribute` https://github.com/microsoft/testfx/blob/master/src/TestFramework/MSTest.Core/Attributes/VSTestAttributes.cs#L68, the attribute is not `sealed` in v2, so you might need to double check if you are using v2. – weichch Mar 26 '20 at 10:23
  • `TestkeeprResult` class is saving test results? – Mehwish Mar 30 '20 at 13:23
  • @Amna `TestResultKeeper` class is an example of how test results / test context data could be saved to variables as per your question. It is a dummy class. – weichch Apr 01 '20 at 05:15
1

For NUnit you can access the result and other details of the test using properties found in TestContext.CurrentContext.

For your problem you can add the following check to the test teardown method

if(TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed) { .... }

Edit to include MSTest:

For MSTest add the following property to your test class

public TestContext TestContext { get; set; }

Then use it by adding the following to TestCleanup

if(TestContext.CurrentTestOutcome == UnitTestOutcome.Passed) { .... }
BoldAsLove
  • 660
  • 4
  • 13