How do I pass reference to active driver between classes - c#

My problem is that when firstname is suppose to be set by the driver in the FetchName method I get an error message that the driver is null. Can I pass the active driver instance in some way so I can continue fetch data?
[TestFixture]
public class TestBase
{
protected IWebDriver driverChrome;
[SetUp]
public void Setup()
{
driverChrome = new ChromeDriver();
}
[TearDown]
public void CleanSite()
{
driverChrome.Quit();
}
}
Class "Tests" where I create all my [test] methods.
public void tests: Testbase
{
[Test]
public void testmethods()
{
string blabla = driverChrome.FindElement(By.id("dsd")).Text;
Reuse.FetchName(out string firstname, out string lastname);
Assert.isTrue(firstname.equals(lastname));
}
}
One Class "Reuse" where I have methods that the [test] methods will use multiple times.
public class Reuse: Testbase
{
[Test]
public void FetchName(out string firstname, out string lastname)
{
firstname = driverChrome.FindElement(By.XPath("/html/body/div[2]/table/tbody[last()]/tr/td[2]/div")).Text;
lastname = driverChrome.FindElement(By.XPath("/html/body/div[2]/table/tbody[last()]/tr/td[2]/div")).Text;
}
}

Reuse class is not a test case. When you add attribute [Test] to the method, the method should contains an assertion. So Reuse should not inherit from Testbase.
If you want to have a class that contains multiple actions, it should be static class.
WebDriver is a standalone process. You can use multiple classes or multiple process to access it. They all will get the same WebDriver.
The example below shows how to change the Reuse class and how to use it.
public static class Reuse
{
public static IWebDriver driverChrome;
public static void FetchName(out string firstname, out string lastname)
{
firstname = driverChrome.FindElement(By.XPath("/html/body/div[2]/table/tbody[last()]/tr/td[2]/div")).Text;
lastname = driverChrome.FindElement(By.XPath("/html/body/div[2]/table/tbody[last()]/tr/td[2]/div")).Text;
}
}
You can call it like this.
public void tests: Testbase
{
[Test]
public void testmethods()
{
string blabla = driverChrome.FindElement(By.id("dsd")).Text;
Reuse.driverChrome = driverChrome;
Reuse.FetchName(out string firstname, out string lastname);
Assert.isTrue(firstname.equals(lastname));
}
}

Related

How to pass custom data to the log4net.Core.LoggingEvent object?

I want to get custom data from the log4net.Core.LoggingEvent object inside Append method of my custom log4net appender.
public sealed class SimpleAppender : AppenderSkeleton
{
protected override void Append(LoggingEvent loggingEvent)
{
// How can I receive my data?
}
}
I know that log4net.Core.LoggingEvent contains Properties property. It has type log4net.Util.PropertiesDictionary. A logger or an appender may attach additional properties to specific events, but I'm not sure that it is what the way I'm looking for. I need to get testId here. I created that testId in the method marked [TestInitialize] attribute.
public class UnitTest1
{
public TestContext TestContext { get; set; }
[TestInitialize]
public void Initialize()
{
Guid testId = Guid.NewGuid();
}
[TestMethod]
public void TestMethod1()
{
ApplicationLogger.LogInfo("TestMethod1 has started.");
}
}
ApplicationLogger class is a simple log4netlogger wrapper which prints result into console. I know that I can do something like this.
ApplicationLogger.LogInfo("Test message", testId);
public static class ApplicationLogger
{
private static readonly log4net.ILog log4netLogger;
public static void LogInfo(Guid testId, string infoMessage)
{
ApplicationLogger.log4netLogger.Info(new LogMessageModel
{
Text = infoMessage,
TestId = testId
});
}
}
But I don't want to set testId into LogInfo() method every time I need to log something. Is there another more more elegant way? Thanks in advance.
Add a static Initialize() function to ApplicationLogger that accepts testId as a parameter and call ApplicationLogger.Initialize(testId) from UnitTest1.Initialize().

Executing Powershell Cmdlets Code in C#

How would I use the code used to create powershell cmdlets in another c# method instead of a powershell script.
I have the following code:
public class Program
{
static void Main(string[] args)
{
var getCommand = new GetCommand { Text = "Hello World"};
//help needed here
}
}
[Cmdlet("Test", "Get")]
public class GetCommand : Cmdlet
{
[Parameter(Mandatory = true)]
public string Text { get; set; }
protected override void ProcessRecord()
{
WriteObject(Text);
}
}
Don't instantiate the GetCommand class - PowerShell will do that for you!
First, you'll need to spin up an instance of the PowerShell class to execute your command:
PowerShell ps = PowerShell.Create();
Then add a CommandInfo reference with the AddCommand method:
ps.AddCommand(new CmdletInfo("Test-Get", typeof(GetCommand)));
And then add your parameter argument:
ps.AddParameter("Text", "Hello World");
Now you can execute it (and collect the output) with the Invoke() method:
var output = ps.Invoke();
foreach(var obj in ouput)
{
Console.WriteLine("Output was: {0}", obj);
}
Extract the logic in a seperate class and call it directly. Use the cmdlet to be, well, just a shell around this new class.
This Seperation of Concerns (SoC) also enables easier unit tests and leads to an overall cleaner architecture.
Extracted Class Greeter.cs
public class Greeter {
public Greeter(string name) {
_Name = name;
}
private string _Name;
public string SayHello() {
return $"Hello {_Name}";
}
public string SayGoodBye() {
return $"So long {_Name}, and thanks for all the fish!";
}
}
CommandLet GetGreetingCommand.cs
[Cmdlet("Greeting", "Get")]
public class GetGreetingCommand : Cmdlet {
[Parameter(Mandatory = true)]
public string Name { get; set; }
protected override void ProcessRecord() {
var greeter = new Greeter(Name);
var greeting = greeter.SayHello();
WriteObject(greeting);
}
}
CommandLet GetGoodByeCommand .cs
[Cmdlet("GoodBye", "Get")]
public class GetGoodByeCommand : Cmdlet {
[Parameter(Mandatory = true)]
public string Name { get; set; }
protected override void ProcessRecord() {
var greeter = new Greeter(Name);
var goodBye = greeter.SayGoodBye();
WriteObject(goodBye);
}
}
Console Main.cs (or any other client-code of Greeter-class)
public static void main(string[] args) {
var greeter = new Greeter(args.FirstOrDefault());
Console.WriteLine(greeter.SayHello());
Console.WriteLine(greeter.SayGoodBye());
}
TestCase
public static void SayingHelloUsesName() {
var sut = new Greeter("Arthur");
var expected = "Hello Arthur";
var actual = sut.SayHello();
Assert.AreEqual(expected, actual);
}
The two concerns here are
- the actual BusinessLogic (Greeter.cs)
- interoperability with PowerShell, providing mechanisms to parameterize the cmdlet, etc. (Get*Command.cs). As you see, the cmdlets really only pass through the calls, while enabling use via PowerShell.
#Mathias R. Jessen ยด answer could be usefull, if you need to call third party cmdlets, but in most cases, there should be an appropriate (non-powershell) API for what you are trying to do.

NUnit test and how to initialize DependencyManager.Resolve

I have the following code that I need to initiate within my integration test in my C# NUnit test.
How can I initialize the DependencyManager.Resolve method please?
Many thanks,
Unit test calls this method
public static Account GetCustomer(string databaseName)
{
Database db = DatabaseFactory.CreateDatabase(databaseName);
using(DbCommand cmd = db...)
{
}
}
CreateDatabase method
public static Database CreateDatabase(string name)
{
IDbFactory factory = DependencyManager.Resolve<IDbFactory>();
return factory.GetDatabase(name);
}
Unit test
[Test]
public void When_I_Call_GetCustomer_A_Customer_Is_Returned()
{
var result = CustomerAccount.GetCustomer(..);
}
Update
DependencyManager implementation shown below
public class DependencyManager
{
public static T Resolve<T>(string key = "", ParamDictionary parameters = null)
{
return Resolver.Resolve<T>(key, parameters);
}
}
private static volatile IDependencyResolver resolver;
...
public static IDependencyResolver Resolver
{
get { return DependencyManager.resolver; }
}
It eventually gets to
public class CastleDependencyContainer : IDependencyBuilder, IDependencyResolver

AutoComplete for string parameter

I have set up a testproject using NUnit and Selenium Webdriver of which you can find a shortened version below.
class ByHolder
{
public readonly string name, path;
public readonly Func<string, By> call;
public ByHolder(string name, string path, Func<string, By> call)
{
this.name = name;
this.path = path;
this.call = call;
}
}
class Page
{
private readonly List<ByHolder> LocatorList = new List<ByHolder>();
public Page()
{
SetUpList();
}
private void SetUpList()
{
AddLocator("Button0", "//button0", By.XPath);
AddLocator("Button1", "button1", By.Id);
...
}
public By Get(string locatorName)
{
var holder = LocatorList.FirstOrDefault(p => p.name.Equals(locatorName));
return holder?.call(holder.path);
}
public void AddLocator(string name, string path, Func<string, By> call)
{
LocatorList.Add(new ByHolder(name, path,call ));
}
}
class PersonelDriver : IWebDriver
{
IWebDriver driver = new FirefoxDriver();
Page page = new Page();
public void Click(string locatorName)
{
driver.FindElement(page.Get(locatorName)).Click();
}
...
}
[TestFixture]
class PageTest
{
private readonly PersonelDriver d = new PersonelDriver();
[Test]
public void ClickTest0()
{
d.Click("Button0");
}
[Test]
public void ClickTest1()
{
d.Click("Button1");
}
...
}
As you can hopefully see I tried implementing a shortened method with a minimum of variables to make longer testcases easier to read mainly for outsiders but also for me, for example.
d.Click("that");
d.EnterText("thisLocator","text");
d.WaitFor("somethingElse");
d.Click("this");
(After using Selenium for some time I find that things can become chaotic quite fast when repeatedly using the driver.FindElement... in the tests themselves.)
Even tough I'm happy with the shortened versions and readability, there is of course no autocomplete or check since i'm handling strings and not IWebElement objects or By references that have been named or put in a specific getter.
What I used to do was the following, but it just felt wrong:
class Locators
{
public By GetButton()
{
return By.Id("button");
}
...
}
I was wondering if there is a way to implement an autocomplete or some other check for the string values when adding for example d.Click("stringvalue");
Thank you in advance.

How to parameterized C# NUnit TestFixtures with multiple browsers

So I am pretty new to webdriver and nunit, I am building out regression tests for my legacy products and have the need to run my tests in multiple browsers and I would like them to be configurable to different integration environments. I have the multiple browsers working but am unsure how to parameterize the test fixtures.
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
public class UnitTest1<TWebDriver> where TWebDriver: IWebDriver, new()
{
PTGeneral General;
[TestFixtureSetUp]
public void SetUp()
{
General = new PTGeneral();
General.Driver = new TWebDriver();
}
I would just use the TestCaseSource attribute to specify the values to each test:
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
public class UnitTest1<TWebDriver> where TWebDriver: IWebDriver, new()
{
// ...
public IEnumerable<string> UrlsToTest
{
get
{
yield return "http://www.example.com/1";
yield return "http://www.example.com/2";
yield return "http://www.example.com/3";
}
}
[TestCaseSource("UrlsToTest")]
public void Test1(string url)
{
// ...
}
[TestCaseSource("UrlsToTest")]
public void Test2(string url)
{
// ...
}
}
The most simple answer to your question is to use [TestCase] attributes for your test methods.
Use the next example:
[TestFixture("sendSomethingToConstructor")]
class TestClass
{
public TestClass(string parameter){}
[TestCase(123)] //for parameterized methods
public void TestMethod(int number){}
[Test] //for methods without parameters
public void TestMethodTwo(){}
[TearDown]//after each test run
public void CleanUp()
{
}
[SetUp] //before each test run
public void SetUp()
{
}
}

Categories

Resources