Replace ScenarioContext.Current in non binding class using context injection - c#

I want to use context injection to remove the obsolete warnings for FeatureContext.Current and ScenarioContext.Current my code.
I have a reporter in a non binding class that requires setup before the test is run.
I have tried making a constructor and instantiating it but the values always return as Null.
In the Setup Step
namespace EclipseWebAutomationV2.Steps
{
[Binding]
class StepSetup
{
public static FeatureContext _featurecontext;
public static ScenarioContext _scenariocontext;
[BeforeTestRun]
public static void InitializeReport()
{
Reporter.ReportInit();
}
[BeforeFeature]
public static void BeforeFeature()
{
Reporter bfeature = new Reporter(_featurecontext, _scenariocontext);
bfeature.ReportFeature();
}
}
}
In the report class:
namespace EclipseWebAutomationV2.Configurations
{
class Reporter
{
private readonly FeatureContext _featurecontext;
private readonly ScenarioContext _scenariocontext;
public Reporter(FeatureContext _featurecontext, ScenarioContext _scenariocontext)
{
this._featurecontext = _featurecontext;
this._scenariocontext = _scenariocontext;
}
public static void ReportInit()
{
//does stuff
}
public void ReportFeature()
{
featureName = extent.CreateTest<Feature>(_featurecontext.FeatureInfo.Title);
}
}
}
_featurecontext always returns null. I was hoping for it to get the current feature context so i can use it to get the title and use it in other parts of the reporting class.
I am having the same issue with _scenariocontext.

The main problem is the Reporter object requires a FeatureContext and ScenarioContext object. When the [BeforeFeature] hook is executing, the ScenarioContext does not exist yet.
The [BeforeFeature] hook supports a couple of overloads, one of which accepts the newly created FeatureContext as an argument.
This coupled with removing the FeatureContext and ScenarioContext objects as dependencies for the Reporter class will solve your problem.
First, change the StepSetup class to remove the dependencies on FeatureContext and ScenarioContext, and alter the [BeforeFeature] to accept a FeatureContext object as an argument:
[Binding]
class StepSetup
{
[BeforeTestRun]
public static void InitializeReport()
{
Reporter.ReportInit();
}
[BeforeFeature]
public static void BeforeFeature(FeatureContext featureContext)
{
var reporter = new Reporter();
reporter.ReportFeature(featureContext);
}
}
Then change the Reporter class to accept a FeatureContext argument in ReportFeature:
class Reporter
{
public static ReportInit()
{
// does stuff
}
public void ReportFeature(FeatureContext featureContext)
{
featureName = extent.CreateTest<Feature>(featureContext.FeatureInfo.Title);
}
}
If the Reporter.ReportFeature method does not use any instance fields, consider making this method a static method as well, and using a static constructor instead of the Reporter.ReportInit() method:
static class Reporter
{
static Reporter()
{
// does stuff
}
public static void ReportFeature(FeatureContext featureContext)
{
featureName = extent.CreateTest<Feature>(featureContext.FeatureInfo.Title);
}
}
Then your StepSetup class becomes even simpler with no need to call a static "init" method on the Reporter class:
[Binding]
class StepSetup
{
[BeforeFeature]
public static void BeforeFeature(FeatureContext featureContext)
{
Reporter.ReportFeature(featureContext);
}
}
See Static Constructors (C# Programming Guide)

Related

Using ITestOutputHelper with Selenium, xUnit and C#

I have recently switched a project from NUnit to xUnit so that ITestOutputHelper can be used to output to a log.
The project is a fairly standard layout
Feature Files->Step Classes->Page Classes->Help Classes. Include in the helper classes we have the hooks.class also. I am using the xUnit runner.
So in my hooks class I have created this
private readonly ScenarioContext _scenarioContext;
private ITestOutputHelper _testOutputHelper;
public Hooks(ScenarioContext scenarioContext, ITestOutputHelper testOutputHelper)
{
_scenarioContext = scenarioContext;
this._testOutputHelper = testOutputHelper;
}
public void WriteOutput(string theMessage)
{
_testOutputHelper.WriteLine(theMessage);
}
Now my question is how do I access the WriteOutput function from the other classes?
Or have I placed it in the wrong class?
Since your hooks class already accepts an ITestOutputHelper object, your other step definitions need only do the same thing. From that point on it's just good old fashioned dependency injection.
If you initialize page models and utility classes in each step definition class, since it appears ITestOutputHelper is already registered in SpecFlow's dependency injection framework, you can just pass references to the helper from constructor to constructor.
For example, add a constructor arg and field to a step definition:
[Binding]
public class LoginSteps
{
private ITestOutputHelper testOutputHelper;
private LoginPage loginPage;
private SomeUtility utility;
public LoginSteps(IWebDriver driver, ITestOutputHelper testOutputHelper)
{
this.testOutputHelper = testOutputHelper;
// Pass the test output helper to a page model
loginPage = new LoginPage(driver, testOutputHelper);
// Pass the test output helper to a utility class
utility = new SomeUtility(testOutputHelper);
}
[Given(#"the user is logged in as ""(.*)"")")]
public void GivenTheUserIsLoggedInAs(string username)
{
testOutputHelper.WriteLine("...");
loginPage.LogIn(username);
}
}
Then the page model and utility class need constructor args and fields:
public class LoginPage
{
private IWebDriver driver;
private ITestOutputHelper testOutputHelper;
public LoginPage(IWebDriver driver, ITestOutputHelper testOutputHelper)
{
this.driver = driver;
this.testOutputHelper = testOutputHelper;
}
// ...
}
public class SomeUtility
{
private ITestOutputHelper testOutputHelper;
public SomeUtility(ITestOutputHelper testOutputHelper)
{
this.testOutputHelper = testOutputHelper;
}
// ...
}
With the help of another Dev got the answer, see below
Step Class TestAppSteps
using Xunit.Abstractions;
[Binding]
public sealed class TestAppSteps : TestAppPage
{
public TestAppSteps(ITestOutputHelper output) : base(output)
{
}
code
}
Page Class TestAppPage
using Xunit.Abstractions;
public class TestAppPage : PageAssertions
{
public TestAppPage(ITestOutputHelper output) : base(output)
{
}
code
}
Utility Class PageAssertions
using Xunit.Abstractions;
public class PageAssertions : SharedClass
{
public PageAssertions(ITestOutputHelper output) : base(output) { }
code inc'
WriteToReport("Pass: URL is correct");
}
Utility Class SharedClass
using Xunit.Abstractions;
public abstract class SharedClass : OutputFunctions
{
public SharedClass(ITestOutputHelper output)
: base(output)
{
}
shared code including
WriteToReport(GetTheCurrentMethod());
}
Abstract Class OutputFunctions
using Xunit.Abstractions;
public abstract class OutputFunctions
{
protected readonly ITestOutputHelper _output;
public OutputFunctions(ITestOutputHelper output)
{
_output = output;
}
public void WriteToReport(string theMessage)
{
_output.WriteLine(theMessage);
}
}

need to call controller's action method into another class in c# mvc

I have created one method in a controller, but I need to call this method into anther class and I don't know how to call it.
my sample code :-
public class ReportController : BaseController
{
private readonly IPermissionService _permissionService;
private readonly ICompaniesService _companyService;
public ReportController(IPermissionService permissionService,
ICompaniesService companyService)
{
this._permissionService = permissionService;
this._companyService = companyService;
}
public void Reporting()
{
// code
}
}
public class Home {
public void Execute()
{
//I need to execute the Reporting method here
}
}
I have tried many things to call my method in another class method but I can't get it to work.
It's a bad design way to have some code in a controller who have to be called in several places. Create a class in your project or in an external DLL who contains this code and call this class in the controllers who need this method.
Create a class somewhere (in you project, or in a class library) :
public class MyClass
{
public MyClass()
{}
public void MyMethod()
{
// Some code here
}
}
And implement this code in your controllers or classes who need this.
public class ReportController : BaseController
{
private readonly IPermissionService _permissionService;
private readonly ICompaniesService _companyService;
public ReportController(IPermissionService permissionService,
ICompaniesService companyService)
{
this._permissionService = permissionService;
this._companyService = companyService;
}
public void Reporting()
{
MyClass myClass = new MyClass();
myClass.MyMethod();
}
}
By the way, if your code doesn't need any instance, you can create a static class, like :
public static class MyClass
{
public static void MyMethod()
{
// Some code here
}
}
public class ReportController : BaseController
{
private readonly IPermissionService _permissionService;
private readonly ICompaniesService _companyService;
public ReportController(IPermissionService permissionService,
ICompaniesService companyService)
{
this._permissionService = permissionService;
this._companyService = companyService;
}
public void Reporting()
{
MyClass.MyMethod();
}
}
There are two ways of accomplishing this. You are using dependency injection in your controller's constructor, so you have two options of doing this (not sure if I have missed any?):
Create an instance of each of your services in the calling method and pass these instances through when instantiating the controller, or
Add a constructor to your home class, set the services and pass them through when instantiating the controller
Option 1:
public class Home
{
public void Execute()
{
// Create the variables that are needed by the constructor
IPermissionService permissionService = new PermissionService();
ICompaniesService companiesService = new CompaniesService();
// Create an instance of your controller and pass through
// the variables created above
ReportController reportController = new ReportController(permissionService, companiesService);
// Now that you have an instance of your controller call the method
reportController.Reporting();
}
}
It works on the same principle as creating an instance of a class and then calling its methods.
Option 2:
public class Home
{
private IPermissionService permissionService;
private ICompaniesService companiesService;
public Home(IPermissionService permissionService, ICompaniesService companiesService)
{
this.permissionService = permissionService;
this.companiesService = companiesService;
}
public void Execute()
{
ReportController reportController = new ReportController(permissionService, companiesService);
reportController.Reporting();
}
}
ReportController reportController = new ReportController();
reportController.Reporting();
As you would any other class that's method isn't static
Please read this answer, they go into a lot more detail than I do

Using Castle Windsor in Windows Form Application

I want to add a logger to the Windows Form Application by using Castle IOC.
I registered the logger like below:
static class Program
{
[STAThread]
static void Main()
{
IWindsorContainer container = new WindsorContainer().Install(FromAssembly.This());
container.Register(Component.For<ICommonLogger>().ImplementedBy(typeof(CommonLogger)).LifeStyle.Singleton);
container.Kernel.Resolver.AddSubResolver(new EAE_Automation.COM.LoggerResolver(container.Kernel));
}
}
Then another form of the application, I tried to use the logger as property but It comes null to the program.
namespace Test.KNXManagement
{
public partial class Test: Form
{
public ICommonLogger Logger { get; set;}
public Tunneling()
{
Logger.Info("Testing.......................");
}
}
}
I think I am missing an important point here
I also register the Form class to resolve sub dependencies.
container.Register(Classes.FromThisAssembly().BasedOn<Form>());
Then also run the application as below
Application.Run(container.Resolve<Test>());
Thats solved my problem.
Thanks everyone.
The following code, based on yours, works perfectly fine for me:
private static IWindsorContainer _container;
static Program()
{
Debug.Listeners.Add(new ConsoleTraceListener());
_container = new WindsorContainer().Install(FromAssembly.This());
_container.Register(Component.For<ICommonLogger>().ImplementedBy(typeof(CommonLogger)).LifeStyle.Singleton);
}
private static ICommonLogger Logger { get; set; }
private static void Main(string[] args)
{
Logger = _container.Resolve<ICommonLogger>();
Logger.Write("Text");
Console.ReadLine();
}
public interface ICommonLogger
{
void Write(string str);
}
public class CommonLogger : ICommonLogger
{
public void Write(string str)
{
Console.WriteLine(str);
}
}
The output of the program in the console is Text.

testContextInstant value is always Null when it was called from logger file to test case file

I have read some information regarding TestContext of MStest and can use it accordingly.
Now my task about TestContext is a little bit different and am confusing how it could work.
The situation related to three files:
In testcase.cs file, TestContext property is in [Test Class]. But in [TestMehtod], I don't want to use like testContextInstance.WriteLine("WRITE TEST PARAMETERS") directly, it will be put in another file named TestLogger.cs.
[TestClass]
public class Test1 : BaseTestTemplate
{
public TestContext TestContext { get; set; }
public static void FixtureSetUp(TestContext testContext)
{
}
public static void FixtureTearDown(TestContext testContext)
{
}
[TestInitialize]
public override void SetUp()
{
}
[TestMethod]
{
Logger.BeginSection("WRITE TEST PARAMETERS"); // instead of testContextInstance.WriteLine("WRITE TEST PARAMETERS");
}
}
In AssemblySetup.cs file, in [AssemblyInitialize], public static void AssemblySetUp(TestContext testContext) is done and it include one function that is InitializeLogging(); In this function, I initialize TestLogger with Logger.RegisterLogChannel(LogChannel.TestLog, new TestLogger()).
[TestClass]
public static class AssemblySetUpClass
{
public static void InitializeLogging()
{
string testContext = "";
Logger.RegisterLogChannel(LogChannel.TestLog, new TestLogger(testContext));
}
[AssemblyInitialize]
public static void AssemblySetUp(TestContext testContext)
{
InitializeLogging();
}
}
Following I add testContextInstance.WriteLine(title) in TestLogger.cs. But in debug, testContextInstance is always null.
public sealed class TestLogger : LoggerBase
{
private TestContext testContextInstance;
public TestLogger(string testContext)
{
}
public override void BeginSection(string title)
{
testContextInstance.WriteLine(title);
base.BeginSection(title);
}
}
I am trying to modify Logger.RegisterLogChannel(LogChannel.TestLog, new TestLogger(testContext)) The purpose is to tell TestLogger, testContext will be called. In TestLogger, I also add private TestContext testContextInstance; and public TestLogger(string testContext)
The problem is still the same, in Warning it said, testContextInstance is never assigned to, will always have its default value null
I hope you could understand my problem. Please give me some idea or solutions on how to handle with it, thank you very much.
You've got this code:
private TestContext testContextInstance;
public TestLogger(string testContext)
{
}
Is the constructor to TestLogger really supposed to be empty? The problem might be as simple as you never assigning your parameter testContext to anything in the constructor body. I would assume that you're supposed to assign it to testContextInstance in the constructor.
private TestContext testContextInstance;
public TestLogger(string testContext)
{
testContextInstance = testContext;
}

How can I make one class solely responsible for creating and providing access to another class

This is how I understand I can implement the singleton pattern in C#:
public class ChesneyHawkes{
private static ChesneyHawkes _instance = new ChesneyHawkes();
public ChesneyHawkes Instance {get{return _instance;}}
private ChesneyHawkes()
{
}
}
What if I want to provide a single instance of an object, so that there can only ever be one, make the access to it public, but only allow it to be created or replaced by another singleton.
// The PuppetMaster should be the only class that
// can create the only existing Puppet instance.
public class PuppetMaster{
private static PuppetMaster_instance = new PuppetMaster();
public static PuppetMaster Instance {get{return _instance;}}
// Like a singleton but can be replaced at the whim of PuppetMaster.Instance
public static Puppet PuppetInstance {get {return Puppet;}}
private PuppetMaster()
{
}
public class Puppet{
// Please excuse the pseudo-access-modifier
puppetmasteronly Puppet(){
}
}
}
// To be accessed like so.
PuppetMaster.Puppet puppet = PuppetMaster.Instance.PuppetInstance;
You don't really need more than one singleton for that. Look at this example:
using System;
// interface for the "inner singleton"
interface IPuppet {
void DoSomething();
}
class MasterOfPuppets {
// private class: only MasterOfPuppets can create
private class PuppetImpl : IPuppet {
public void DoSomething() {
}
}
static MasterOfPuppets _instance = new MasterOfPuppets();
public static MasterOfPuppets Instance {
get { return _instance; }
}
// private set accessor: only MasterOfPuppets can replace instance
public IPuppet Puppet {
get;
private set;
}
}
class Program {
public static void Main(params string[] args) {
// access singleton and then inner instance
MasterOfPuppets.Instance.Puppet.DoSomething();
}
}

Categories

Resources