3

I am using MSTEST C# in selenium webdriver. Hierarchy of my project is

Level1-MainProjectfile

     Level2-Properties

     Level2-Refernces

     Level2-AppObj(folder)

               Level3-DP(folder)

                        Level4-dpo.cs

                        Level4-dpc.cs

               Level3-TestRail(folder)

                         Level4-TestRailpm.cs

                         Level4-TestRailpo.cs

               Level3-gmethods.cs

      Level2-AUtomationCode.cs

      Level2-log4net.config

Now My Unit Testcases are present in AutomationCode.cs file this is the main project file. The code in my AutomationCode.cs file is

    public class AutomationCode
    {
        private IWebDriver WDriver;
        private log4net.ILog Testlog;
    
    
        [TestInitialize]
        public void wd()
        {
            WDriver = Helper.GetWebDriver(helperconst.browserType.Chrome);
            Testlog = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        }
        [Priority(1)]
        [TestMethod]
        public void search()
        {
            Testlog.Info("Test ID:001, This test will select the criteria and update the customer dropdown");
    
            Testlog.Info("Step 1/1 : Select customer from cutomer dropdown");
            var dc = gmethods.GetSelectElement(WDriver, dpo.customermenu);
            dc.SelectByText(dpc.customer);
        }
///[Ignore]
        [Priority(2)]
        [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
        public void TestRailCall()
        {
            TestRailpm a = new TestRailPM();
            a.testrail();
        }

        [TestCleanup]
        public void CleanUp()
        {
            WDriver.Close();
            WDriver.Quit();
        }
    }

In dpo page:

public static class dpo
{
    public const string customermenu = "[data]";
}

In dpc page

public static class dpc
{
    public const string customer = "A";
}

In gmethods page:

static public SelectElement GetSelectElement(IWebDriver drv, string elem)
{
    SelectElement a = new SelectElement(drv.FindElement(By.CssSelector(elem)));
    return a;
}

In TestRailPO file the code is

    namespace Automation.AppObj.TestRail
{
    public class TestRailPO
    {

        public class TestResultKeeper
        {
            public static TestResult TestResult { get; set; }
            public static UnitTestOutcome TestOutcome => UnitTestOutcome.Failed;

            //TestResult ?? Outcome ?? UnitTestOutcome.Failed;

            public static bool IsPassed => TestOutcome == UnitTestOutcome.Passed;
            public static Exception Exception { get; set; }

            
        }

        public class TestMethodAttribute : Attribute
        {
            public virtual TestResult[] Execute(ITestMethod testMethod)
            {
                return new TestResult[] { };
            }
        }

        public class LogTestTestMethod : TestMethodAttribute
        {

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

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

                return new[] { testResult };


            }

        }
    }

In testrailpm.cs code is :

public class TestRailPM
{

   
    string testRailUrl = "https://test.testrail.io/";
    string testRailUser = "test@gmailcom";
    string testRailPassowrd = "test";
    int projectId = 1;
    int milestoneId = 1;
    int suiteId = 1;
    int testRailUserId = 1;
    string[] testCaseIds = { "12345", "21343" };


    public void testrail()
    {
        //Create Test Run in TestRail
        //Pass "true" against 'includeAll' parameter to insert all test cases in a suite; "false" to add specific test case id
        string testRunID = CreateTestRun.CreateRun(testRailUrl, testRailUser, testRailPassowrd, projectId, suiteId, milestoneId, "Automation of TestCases", "Automation of TestCases", testRailUserId, false, testCaseIds);
        int testRunIdInInt = Convert.ToInt16(testRunID);

        //Get TestCases Ids of a Run

        int[] newTestRunCaseIds = GetTestCases.getTestCaseIds(testRailUrl, testRailUser, testRailPassowrd, testRunIdInInt, true);
        int[] originalTestCaseIds = GetTestCases.getTestCaseIds(testRailUrl, testRailUser, testRailPassowrd, testRunIdInInt, false);

        //Add Result for Single Test Case in a Test Run
        /* testCaseStatus int The ID of the test status. The built-in test rail statuses have the following IDs:
        1 Passed
        2 Blocked
        3 Untested (not allowed when adding a result)
        4 Retest
        5 Failed
        */


        int singleTestCaseId = 716869;
        UpdateTestRun.updateSingleTestCaseInATestRun(testRailUrl, testRailUser, testRailPassowrd, testRunIdInInt, singleTestCaseId, TestContext.CurrentTestOutcome == UnitTestOutcome.Passed ? 1 : 5, "testCaseComments", testRailUserId);


        /*
        // Add Result for Multiple Test Cases in a Test Run at a time
        int[] testCaseIdsToUpdateResults = { 584003, 584004, 584005, 584006, 584007, 584008, 584009, 584075, 584076, 584213, 604458, 716869, 716870, 716871, 716872};
        int[] testCaseStatuses = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
        string[] testCaseComments = { "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed", "This case is passed"};
        UpdateTestRun.UpdateTestRunResults(testRailUrl, testRailUser, testRailPassowrd, testRunIdInInt, newTestRunCaseIds, testCaseStatuses, testCaseComments, testRailUserId);
        */


    }


}

I am using MStest C#. All I want is to Run my main project file that is AutomationCode.cs and the result of test case that would be "Pass/Fail" will get saved in a variable or attribute etc that is in TestRailpo.cs file testkeeperresult or any other attribute. Of course, the result saved would be either pass or fail but here is the main thing. I need to pass that result in the form of numbers that is 1 or 5. 1 for pass and 5 for Fail. That result I need to pass in TestRailpm.cs file in Resultoftestcase.

UpdateTestRun.updateSingleTestCaseInATestRun(testRailUrl, testRailUser, testRailPassowrd, testRunIdInInt, singleTestCaseId, Resultoftestcase, "testCaseComments", testRailUserId);
           }

I have called the TestRail() method from TestRail.pm file to AutomationCode.cs before testcleanup because I want to update TestRail after my unit test cases are executed. Keeping in view of my detailed description kindly help me in code to pass the result in the form of 1 or 5 in testRail.pm file. Please guide me how can I do that and what changes would be required?

Modus Tollens
  • 5,083
  • 3
  • 38
  • 46
Mehwish
  • 55
  • 9
  • You say you are using NUnit but your test code is definitely not NUnit - it is not using NUnit attributes, for example. OTOH, your custom attribute is definitely based on NUnit. – Charlie Mar 25 '20 at 09:57
  • You can't expect an NUnit custom attribute to do anything for non-NUnit tests. – Charlie Mar 25 '20 at 09:58
  • @Charlie can you please provide the solution how can I do this? – Mehwish Mar 25 '20 at 10:20
  • @Anna I would love to answer the question! However, I can only comment because you have still not clarified whether you want to use the NUnit or MsTest framework. You can't use both! If it's NUnit, please try with new test code that uses NUnit only. – Charlie Mar 25 '20 at 17:14
  • Does your code compile? If it does, then you are referencing two test frameworks. Remove the reference to the one you do not want and correct any errors if you can. If you end up using NUnit, I can answer. If MsTest, then somebody who knows that framework can take a shot! – Charlie Mar 25 '20 at 17:16
  • @Charlie I have removed the Nunit reference. and i want to use MStest. – Mehwish Mar 26 '20 at 05:01
  • In that case, of course, your special NUnit attribute implementing `IWrapTestMethod` is no longer possible. You need to investigate whether MsTest supports the same sort of thing. If you change your tags, you might get an MsTest expert to show up here! – Charlie Mar 26 '20 at 17:59
  • No one here to help? – Mehwish Mar 30 '20 at 11:05
  • @Amna are you using testrail API to update the test result? – Pankaj Devrani Apr 03 '20 at 08:07
  • @Amna As far as I understand You have created a wrapper(CreateTestRun and UpdateTestRun) against TestRail API to create a testrun and update your test result in testrail. Can you please tell are you geting the testRunIdInInt, singleTestCaseId, parameters in the UpdateTestRun.updateSingleTestCaseInATestRun() method once you call TestRailpm.testrail() method? – Pankaj Devrani Apr 03 '20 at 09:10
  • @Amna Can you share the code of CreateTestRun and UpdateTestRun? – Pankaj Devrani Apr 03 '20 at 09:10

2 Answers2

0

In principal this is the same question you asked here and here

This is the answer given...

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) { .... }

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
  • Incase its not clear, you can use the code in your teardown and call the appropriate function there. – BoldAsLove Mar 31 '20 at 17:55
  • considering this for MStest i have added what you mentioned above. But how can I pass that result in the form of 1 or 5(1 for pass5 for Fail) to the TestRailpm.cs file in parameter `Resultoftestcase`? – Mehwish Apr 01 '20 at 12:12
  • inside the test teardown you call your method and pass in a 1 or 5 depending on the result. So in the test teardown you could add UpdateTestRun.updateSingleTestCaseInATestRun(testRailUrl, testRailUser, testRailPassowrd, testRunIdInInt, singleTestCaseId, TestContext.CurrentTestOutcome == UnitTestOutcome.Passed ? 1 : 5, "testCaseComments", testRailUserId); – BoldAsLove Apr 01 '20 at 14:53
  • @BoladAsLove could you please give an example considering my code how to call method in teardown test? – Mehwish Apr 01 '20 at 15:09
  • @Amna I gave an example in the comment above. If you ask more specific questions about things your having trouble understanding I can try to answer them. – BoldAsLove Apr 02 '20 at 14:31
  • I call UpdateTestRun.updateSingleTestCaseInATestRun(testRailUrl, testRailUser, testRailPassowrd, testRunIdInInt, singleTestCaseId, TestContext.CurrentTestOutcome == UnitTestOutcome.Passed ? 1 : 5, "testCaseComments", testRailUserId); in test tear down how can I update testresult of testcases in the testrun (containing all testcases) created at first when test execution was started? – Mehwish Apr 07 '20 at 07:35
  • for multiple testcase results how can I use this if(TestContext.CurrentTestOutcome == UnitTestOutcome.Passed) { .... }? – Mehwish Apr 08 '20 at 13:50
  • The test teardown is ran after every test – BoldAsLove Apr 08 '20 at 14:50
  • But it will pick the latest testcase result. – Mehwish Apr 08 '20 at 14:58
  • Yes, so you keep track of all your test results by adding them to the array after each test case. Then if you want to do something when the entire test suite is done you can add a test suite cleanup method and access the test results you previously saved there. – BoldAsLove Apr 08 '20 at 15:09
  • How can I save the testresults in an array? Could you please help me in this regard showing an example? – Mehwish Apr 08 '20 at 15:10
  • For simplicity you can just save all test case results to a list and walk the list when your done. Add member variable List results = new List() to your test suite, then in test teardown just call results.add(TestContext). Then in the test suite cleanup you can access that list. – BoldAsLove Apr 08 '20 at 15:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/211229/discussion-between-amna-and-boldaslove). – Mehwish Apr 08 '20 at 15:57
0

Please add a test context property in you automationcode class, something like below :

public class AutomationCode
    {
        private IWebDriver WDriver;
        private log4net.ILog Testlog;
        public TestContext TestContext { get; set; }
    }

Now add the below code in your cleanup() method call the method which will update the test result in TestRail. Something like this :

[TestCleanup]
        public void CleanUp()
        {
            WDriver.Close();
            WDriver.Quit();

            TestRailpm a = new TestRailPM();

            if (TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Passed))
            {
                UTestResultKeeper.TestResult.Outcome = UnitTestOutcome.Passed;
                a.Resultoftestcase = "1";

            }
            else if (TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Failed)|| TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Timeout)|| TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Inconclusive))
            {
                TestResultKeeper.TestResult.Outcome = UnitTestOutcome.Failed;
                a.Resultoftestcase = "5";
            }
            //now that TestReultKeeper is updated wi can call the API method to update the test rail
            a.testrail();
        }

I am not sure if TestRailpm.Resultoftestcase property can be accessed or not as you have not shared the whole code but I have called it directly to update the property and later update the result in Testrail.

Let me know If this does not work for you, I have a simpler way of updating the testresult in testrail using the same testrail API.

The Simpler way to achieve this is downloading TestRail API Client from here and then updating the testrail test cases using the test rail API

 public class UpdateTestResult
{
    /// <summary>
    /// Update the test result in testrail
    /// </summary>
    /// <param name="serverUrl">e.g. "http://<server>/testrail/</param>
    /// <param name="userName">username to be used</param>
    /// <param name="userPassword">password of the user</param>
    /// <param name="testCaseID">testrail test case ID</param>
    /// <param name="testResult">stauts of the test. e.g. :1 is passed and 5 is failed.</param>
    public void UpdateResultInTestRail(string serverUrl, string userName, string userPassword, string testCaseID, int testResult)
    {
        APIClient client = new APIClient("http://<server>/testrail/") { User = "userName", Password = "userPassword" };

        var data = new Dictionary<string, object>
                            {
                                { "status_id", testResult },
                                { "comment", "This test worked fine!" }
                            };

        client.SendPost("add_result/:"+ testCaseID, data);
    }
}

And now you can call this class method in cleanup method of the test method. Something like this :

        [TestCleanup]
    public void CleanUp()
    {
        UpdateTestResult updateResult = new UpdateTestResult();
        if (TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Passed))
        {
            updateResult.UpdateResultInTestRail("serverUrl", "username", "Password", "testcaseID", 1);
        }
        else if (TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Failed)|| TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Timeout)|| TestContext.CurrentTestOutcome.Equals(UnitTestOutcome.Inconclusive))
        {
            updateResult.UpdateResultInTestRail("serverUrl", "username", "Password", "testcaseID", 5);
        }
    }

To learn more about testrail API you can refer this link. For API results you can even refer this link.

Pankaj Devrani
  • 510
  • 1
  • 10
  • 28
  • `TestRailpm.Resultoftestcase` property cannot be accessed like this. It did not work for me. Could you please share your way of updating TestResult in testRail using same TestRail API? – Mehwish Apr 03 '20 at 13:29
  • @Amna does updating UTestResultKeeper.TestResult.Outcome changes the status of `TestRailpm.Resultoftestcase` if not can you tell me how `TestRailpm.Resultoftestcase` can be accessed? – Pankaj Devrani Apr 04 '20 at 08:08
  • @Amna Can you share the whole code of TestRailpm.cs? – Pankaj Devrani Apr 04 '20 at 08:24
  • I have updated code in the question in TestRailpm.cs file. Please see. – Mehwish Apr 06 '20 at 05:28
  • Also I need to update test case in a single testrun created at first when execution is started. Now i Want to update all my testcase result in that testrun. – Mehwish Apr 07 '20 at 07:13
  • What do you mean by update test case, do you want to modify the test or do you want to update test result? You have confused me. Can you please ask a separate question, as this question does not really ask what you are trying to achieve. – Pankaj Devrani Apr 07 '20 at 21:37
  • No i dont want to update testcase. I want to update testcase result. – Mehwish Apr 08 '20 at 05:35