SpecFlowOSS / SpecFlow

#1 .NET BDD Framework. SpecFlow automates your testing & works with your existing code. Find Bugs before they happen. Behavior Driven Development helps developers, testers, and business representatives to get a better understanding of their collaboration
https://www.specflow.org/
Other
2.25k stars 754 forks source link

Extent report is not giving proper report when used with specflow runner + Parallel execution #2487

Open akiladevraj opened 3 years ago

akiladevraj commented 3 years ago

SpecFlow Version

3.9.7

Which test runner are you using?

SpecFlow+ Runner

Test Runner Version Number

3.9.7

.NET Implementation

.NET 5.0

Project Format of the SpecFlow project

Classic project format using packages.config

.feature.cs files are generated using

SpecFlow.Tools.MsBuild.Generation NuGet package

Test Execution Method

Visual Studio Test Explorer

SpecFlow Section in app.config or content of specflow.json

No response

Issue Description

I am using specflow runner report + Extent report in my project When i dont execute tests in parallel Extent report is generated properly, but when i set the testThreadCount=3 in default.srprfile, the Extent report does not give the complete report, out of 5 scenarios executed it prints only 3 or 2 or sometimes 1 scenario report. Attached below my Extent reporting hooks. Please let me know how to fix this issue. using System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using AventStack.ExtentReports; using AventStack.ExtentReports.Gherkin.Model; using AventStack.ExtentReports.MarkupUtils; using AventStack.ExtentReports.Reporter; using BoDi; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using SFramework.APIServices.Services; using SFramework.ParallelConfig; using TechTalk.SpecFlow; namespace SciexOneOmicsFramework.CommonServices { [Binding] public sealed class ExtentReportHooks { private readonly OneOmicsWorld _oneomicsWorld; private static bool _extentSetting; private static ExtentReports _extentReport; [ThreadStatic] private static ExtentTest _scenario; public static Stopwatch Timer = new(); [ThreadStatic] private static ExtentTest FeatureName; private static string _driverPath; private string _logMessage; public IMarkup JsonDataPrinter { get; private set; } private static readonly Stopwatch Stopwatch = new(); private static bool _jsonPrinter; private static bool _isUIAutomation;

    [ThreadStatic] private static ScenarioContext _scenarioContext;

    public ExtentReportHooks(OneOmicsWorld world)
    {
         _oneomicsWorld = world;

    }

    [BeforeTestRun(Order=0)]
    public static void InitializeExtentBeforeTestRun()
    {
        _driverPath = Environment.GetEnvironmentVariable("EXPECTED_FOLDER_PATH");
        var ac = new AppConfigDataReader();
        _extentSetting = ac.ExtentReportSetting;
        _isUIAutomation = ac.UISetting;
        if (_extentSetting)
        {
            _extentReport = new ExtentReports();
            _extentReport.AttachReporter(ExtentReportPathConfig());
        }
    }

    [AfterTestRun(Order = 0)]
    public static void PublishReport()
    {
        if (_extentSetting) _extentReport.Flush();
    }

    [BeforeFeature(Order = 0)]
    public static void BeforeFeature(FeatureContext featureContext)
    {
        FeatureName = _extentReport.CreateTest<Feature>(featureContext.FeatureInfo.Title);
    }

    [BeforeScenario(Order = 0)]
    public void Extent_BeforeScenario(ScenarioContext scenarioContext, ObjectContainer objectContainer)
    {
        _oneomicsWorld.ObjectContainer = objectContainer;
        //  _oneomicsWorld.ScenarioContext = scenarioContext;
        _scenarioContext = scenarioContext;
        var driverPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        Timer.Restart();
        _scenario = FeatureName.CreateNode<Scenario>(_scenarioContext.ScenarioInfo.Title);

    }

    [AfterScenario(Order = 1)]   // Order is not given as zero because, zero is used in all the stepdefination class during teardown/delete of oneomics objects created
    public void AfterScenario()
    {
        Timer.Stop();
        Stopwatch.Stop();
    }

    [AfterStep(Order = 0)]
    public void PrintScenariosAndScenarioStatusInReport()
    {

        if (_extentSetting)
        {
            var stepType = _scenarioContext.StepContext.StepInfo.StepDefinitionType.ToString();
            var pInfo = typeof(ScenarioContext).GetProperty("ScenarioExecutionStatus",
                BindingFlags.Instance | BindingFlags.Public);
            if (!(pInfo is null))
            {
                var getter = pInfo.GetGetMethod(true);
                var testResult = getter.Invoke(_scenarioContext, null);

                if (_scenarioContext.TestError == null)
                {
                    PassSteps(stepType);
                }
                else if (_scenarioContext.TestError != null)
                {

                    if (_isUIAutomation)
                        FailStepsWithImage(stepType);
                    else
                        FailSteps(stepType);
                }

                              if (testResult.ToString() == "StepDefinitionPending") PendingSteps(stepType);
            }

            _logMessage = "";
        }
    }

    public void PendingSteps(string stepType)
    {
        if (stepType == "Given")
            _scenario.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text)
                .Skip("Step Definition Pending");
        else if (stepType == "When")
            _scenario.CreateNode<When>(_scenarioContext.StepContext.StepInfo.Text)
                .Skip("Step Definition Pending");
        else if (stepType == "Then")
            _scenario.CreateNode<Then>(_oneomicsWorld.ScenarioContext.StepContext.StepInfo.Text)
                .Skip("Step Definition Pending");
    }

    public void FailSteps(string stepType)
    {
        if (stepType == "Given")
            _scenario.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text)
                .Fail(_scenarioContext.TestError.Message).Log(Status.Info, _oneomicsWorld.ExtentReport._logMessage);
        else if (stepType == "When")
            _scenario.CreateNode<When>(_scenarioContext.StepContext.StepInfo.Text)
                .Fail(_scenarioContext.TestError.Message).Log(Status.Info, _oneomicsWorld.ExtentReport._logMessage);
        else if (stepType == "Then")
            _scenario.CreateNode<Then>(_scenarioContext.StepContext.StepInfo.Text)
                .Fail(_scenarioContext.TestError.Message).Log(Status.Info, _oneomicsWorld.ExtentReport._logMessage);
    }

    public void FailStepsWithImage(string stepType)
    {
        var screenCapture = CaptureScreenShotOnFailure(_oneomicsWorld.Driver, _scenarioContext.ScenarioInfo.Title.Trim());
        if (stepType == "Given")
            _scenario.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text)
                .Fail(_scenarioContext.TestError.Message, screenCapture);
        else if (stepType == "When")
            _scenario.CreateNode<When>(_scenarioContext.StepContext.StepInfo.Text)
                .Fail(_scenarioContext.TestError.Message, screenCapture);
        else if (stepType == "Then")
            _scenario.CreateNode<Then>(_scenarioContext.StepContext.StepInfo.Text)
                .Fail(_scenarioContext.TestError.Message, screenCapture);
    }

    public void PassSteps(string stepType)
    {
        if (stepType == "Given")
        {
            if (_jsonPrinter)
            {
                _scenario.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text)
                    .Log(Status.Info, _oneomicsWorld.ExtentReport.JsonDataPrinter);
                _jsonPrinter = false;
            }
            else
            {
                _scenario.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text)
                    .Log(Status.Info, _oneomicsWorld.ExtentReport._logMessage);
            }
        }
        else if (stepType == "When")
        {
            _scenario.CreateNode<When>(_scenarioContext.StepContext.StepInfo.Text)
                .Log(Status.Info, _oneomicsWorld.ExtentReport._logMessage);
        }
        else if (stepType == "Then")
        {
            _scenario.CreateNode<Then>(_scenarioContext.StepContext.StepInfo.Text)
                .Log(Status.Info, _oneomicsWorld.ExtentReport._logMessage);
        }
        else if (stepType == "And")
        {
            _scenario.CreateNode<And>(_scenarioContext.StepContext.StepInfo.Text)
                .Log(Status.Info, _oneomicsWorld.ExtentReport._logMessage);
        }
    }

    public void LogInfoBlock(string jsonMessage)
    {
        _jsonPrinter = true;
        JsonDataPrinter = MarkupHelper.CreateCodeBlock(jsonMessage, CodeLanguage.Json);
    }

    public void LogInfo(string message)
    {
        _logMessage = Convert.ToString(message);
    }

       public static MediaEntityModelProvider CaptureScreenShotOnFailure(RemoteWebDriver driver, string name)
    {
        var screenShot = ((ITakesScreenshot)driver).GetScreenshot().AsBase64EncodedString;
        return MediaEntityBuilder.CreateScreenCaptureFromBase64String(screenShot).Build();
    }
}

}


Default.srprofile <?xml version="1.0" encoding="utf-8"?>