I an new in specflow i am implementing framework. When i create one feature file with multiple scenario and execute my test than it open one browser instance and run successful when i add one more feature file with multiple scenario and execute my test than it launch multiple browser instance one instance for each scenario can anyone help me out what's wrong in my code
Start.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TechTalk.SpecFlow;
namespace Orange_HRM
{
class Start : SeleniumDriver
{
[BeforeScenarioBlock]
public void Setup()
{
Intitialize();
WebDriver.Navigate().GoToUrl(BaseAddress);
}
[AfterScenarioBlock]
public void TearDown()
{
Close();
}
}
}
SeleniumDriver.cs
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Orange_HRM
{
class SeleniumDriver
{
public static IWebDriver WebDriver;
public static string BaseAddress
{
get { return Constants.Url; }
}
public static void Intitialize()
{
WebDriver = new ChromeDriver();
WebDriver.Manage().Window.Maximize();
TurnOnWait();
}
public static void Navigate()
{
WebDriver.Navigate().GoToUrl(BaseAddress);
}
public static void Close()
{
WebDriver.Close();
}
public static void Quit()
{
WebDriver.Quit();
}
private static void TurnOnWait()
{
WebDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
WebDriver.Manage().Timeouts().PageLoad = TimeSpan.FromMinutes(2);
}
}
}
You are using SpecFlow of techtalk.
Concept name is Hooks.
to perform automatic logic operations at specific timings.So, hooks are event bindings.
running tests in multiple threads with SpecFlow+ Runner.
So, you can put orders,
class Start : SeleniumDriver
{
[BeforeScenario(Order = 0)]
public void Setup()
{
Intitialize();
WebDriver.Navigate().GoToUrl(BaseAddress);
}
[BeforeScenario(Order = 1)]
public void TearDown()
{
Close();
}
}
i like to suggest you dont use them, Bindings Class without Hooks.
i.e. [BeforeTestRun] [AfterTestRun] use them instead.
[AfterScenario]
public void CleanUp()
{
if (seleniumDriver != null)
{
SeleniumDriver.Dispose();
seleniumDriver = null;
}
}
You can initialise and close the driver at Test Run level instead of scenario level. And maintain the url navigation alone at Scenario level. So that the driver will be initiated before test starts and quit after the test completes. Also the page will get refreshed before each scenario run.
namespace Orange_HRM
{
class Start : SeleniumDriver
{
[BeforeTestRun]
public static void Setup()
{
Intitialize();
}
[AfterTestRun]
public static void TearDown()
{
Quit();
}
[AfterScenarioBlock]
public void navigateToUrl()
{
WebDriver.Navigate().GoToUrl(BaseAddress);
}
}
}
Also you have used WebDriver.Close() instead WebDriver.Quit(). If we use WebDriver.Close() for the main window, then session will be terminated. Then if we try to access the same webdriver object again, it will throw No such session error.
WebDriver.Close() is meant for closing child window if we are working with mulitple windows. So to close main window, we have to use WebDriver.Quit() directly.
Related
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
public List<test> testL_I_A;
// doesn't see "testL_I_A" instance name
te = new List();
public enum TypeE{
pistol, shotgun, sword
}
static void Main()
{
Console.WriteLine("Hello World!");
}
public class test {
TypeE tpEI;
public Action activateA;
}
}
it also doesn't see instance's name of classes "program" or "test" if i'm creating them
I have a use case which denotes below steps
I am trying to implement it using POM in Nunit.
Open Login Form
Feed the data in the username and password fields using Excel.
3a. If the credentials are correct
a)Log the test case as passed
b)Click on Log Off link
4.Close the remaining browser window
3b.If the credentials are incorrect
a) Log the test case as failed
b) Clear the username and password textboxes
c) No need to close the browser window.
Now the issue is already driver is instantiated in [Setup] in Main Class.
How do we instantiate the browser window again in case the login is successful.
I am adding the below code
Login Object Class
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.PageObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PracticePrograms.PageObjectsWithPageFactory
{
public class VSSLoginObjects
{
[FindsBy(How = How.Id, Using = "userNameOldLook")]
public IWebElement Userid { get; set; }
[FindsBy(How = How.XPath, Using = "//input[#type='password']")]
public IWebElement Password { get; set; }
[FindsBy(How = How.XPath, Using = "//a[contains(text(),'login')]")]
public IWebElement Btn_Login { get; set; }
[FindsBy(How = How.XPath, Using = "//li[contains(text(),'Login failed')]")]
public IWebElement Lbl_Login_Failed { get; set; }
[FindsBy(How = How.XPath, Using = "//a[contains(text(),'Logoff')]")]
public IWebElement lnk_logoff;
public VSSLoginObjects()
{
PageFactory.InitElements(DriverInstance.driver, this);
}
public void Login_QAPortal()
{
Userid.SendKeys("v0c1344");
Wait.UntilElementDisplayed(DriverInstance.driver, Password);
Password.SendKeys("welcome5");
Btn_Login.Click();
//return new QAPortal_LandingPage_Objects();
}
public void Test_Login_QA_Portal()
{
String Excel = #"C:\\Selenium Files\\TestData.xlsx";
int length = ExcelClassTemp.GetRowCount(Excel, 3);
for (int i = 2; i <= length; i++)
{
String data = ExcelClassTemp.ReadExcel(Excel, 3, i, 1);
String upper_data = data.ToUpper();
Userid.SendKeys(upper_data);
Password.SendKeys("Welcome567");
Btn_Login.Click();
if (DriverInstance.driver.PageSource.Contains("Trucks Portal"))
{
Console.WriteLine("User Credentials" + upper_data + "Passed");
lnk_logoff.Click();
DriverInstance.driver.Close();
}
else
{
Console.WriteLine("User Credentials" + upper_data + "Failed");
Userid.Clear();
Password.Clear();
}
}
}
}
}
Adding the Main Class
Main Class
using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NUnit.Framework;
using OpenQA.Selenium.Chrome;
namespace PracticePrograms.PageObjectsWithPageFactory
{
public class Tests
{
[SetUp]
public void setup()
{
DriverInstance.driver = new ChromeDriver();
DriverInstance.driver.Navigate().GoToUrl("Go to Url");
DriverInstance.driver.Manage().Window.Maximize();
}
[Test]
public void Perform_VSS_Login()
{
VSSLoginObjects login = new VSSLoginObjects();
login.Test_Login_QA_Portal();
}
}
}
Make few changes :
the reference DriverInstance.driver declare this as global.
and when you are creating object of VSSLoginObjects in your Test method like :
VSSLoginObjects login = new VSSLoginObjects();
Pass the reference of DriverInstance.driver in new VSSLoginObjects();
Something like : VSSLoginObjects(reference of driver object) .
Explanation : When you create the object of any class and pass the reference , a parameterized constructor will be called.
I believe this constructor will be called:
public VSSLoginObjects()
{
PageFactory.InitElements(DriverInstance.driver, this);
}
I am trying to implement an InterceptAttribute which should intercept any method I add the attribute to. I have it working in a WebAPI solution, however, I cannot get it to work in an MVC 5 application. The code is the same in both projects. The following code is the attribute I created.
using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Attributes;
using Ninject.Extensions.Interception.Request;
namespace Questionnaire.Common.InterceptAttributes
{
public class InterceptCacheAttribute : InterceptAttribute
{
public double TimeOut { get; set; }
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
var cacheInterceptor = request.Kernel.Get<CacheInterceptor>();
cacheInterceptor.TimeOut = TimeOut;
return cacheInterceptor;
}
}
}
The CacheInterceptor code is as follows:
using System;
using System.Text;
using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Request;
namespace Questionnaire.Common.Interceptors
{
public class CacheInterceptor : IInterceptor
{
[Inject]
public ICaching Cache { get; set; }
public double TimeOut { get; set; }
public void Intercept(IInvocation invocation)
{
var minutes = Cache.TimeOutMinutes;
if (Math.Abs(TimeOut - default(double)) > 0)
{
minutes = TimeOut;
}
invocation.ReturnValue = Cache.Get(GenerateCacheKey(invocation.Request), minutes, delegate
{
invocation.Proceed();
return invocation.ReturnValue;
});
}
private static string GenerateCacheKey(IProxyRequest request)
{
var sb = new StringBuilder(request.Method.Name).Append(".");
foreach (var argument in request.Arguments)
{
if (argument == null)
{
sb.Append("null");
}
else if (argument is string && argument.ToString().Length < 50)
{
sb.Append((string)argument);
}
else
{
sb.Append(argument.GetHashCode());
}
sb.Append(".");
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
}
}
Finally I added the attribute to the following method.
using System.Configuration;
using Questionnaire.Common.InterceptAttributes;
namespace Questionnaire.Common.Utility
{
public class ConfigurationUtilities
{
[InterceptCache(TimeOut = 1440)]
public virtual string GetEnvironmentConnectionString(string name)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[name + "_" + HostEnvironment];
return connectionStringSettings != null ? connectionStringSettings.ConnectionString : null;
}
}
}
Code execution never enters into the InterceptCacheAttribute class. I have put debug points within that class and the CacheInterceptor class and the debug points are never hit. The method the attribute is on executes just fine, but, I want it to be intercepted and that is not happening. I have the same code in a different project. That project is a WebAPI project which works great. The methods are intercepted and everything functions as it should. Can someone explain to me why I can't get it to work in the MVC 5 application? I would greatly appreciate it.
answer to BatteryBackupUnit's question:
The answer is I can't. The following is my NinjectWebCommon.cs class.
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Mayo.Questionnaire.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Mayo.Questionnaire.App_Start.NinjectWebCommon), "Stop")]
namespace Questionnaire.App_Start
{
using System;
using System.Web;
using System.Web.Http;
using System.Linq;
using ApplicationExtensions;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
foreach (var module in from assembly in AppDomain.CurrentDomain.GetAssemblies()
select assembly.GetNinjectModules()
into modules
from module in modules
where !kernel.GetModules().Any(m => m.Name.Equals(module.Name))
select module)
{
kernel.Load(module);
}
}
}
}
Inside the RegisterServices method every assembly in the application is iterated over and any classes that inherit from NinjectModule are loaded. However, I can't verify that it is working because I can't debug it. I have tried, but, execution is never stopped within the class. I know that the class is being instantiated and that the modules are being loaded because I have bindings in those modules that are working, however, I can't verify it.
Say I have a scenario that uses steps that are contained in two different classes. Is there a way for both of them to have a handle to the same IWebDriver instance without going through ScenarioContext.Current["webdriverVariableName"]?
That's so ugly. Is there a cleaner way?
I was going to make a class with a public static IWebDriver property that gets assigned at the start of every scenario, so that all my steps could refer to it, but I don't think that will work when I start to run them in parallel, as each scenario would overwrite the global driver.
Specflow offers a Dependency Injection mecanism, so you could get your web driver instance injected in your steps.
See https://github.com/techtalk/SpecFlow/wiki/Context-Injection
See the "Avanced options" section.
I have just started using Specflow but this appears to work;
Create a class which takes IObjectContainer as a constructor and has a BeforScenario method to create the WebDriver instance;
[Binding]
public class WebDriverSupport
{
private readonly IObjectContainer _objectContainer;
public WebDriverSupport(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario]
public void InitializeWebDriver()
{
var webDriver = DriverFactory.CreateDriver();
_objectContainer.RegisterInstanceAs<RemoteWebDriver>(webDriver);
}
}
Create your step classes with a constructor which take RemoteWebDriver;
[Binding]
public class POCSteps
{
private readonly IdlWebDriver _driver;
public POCSteps(IdlWebDriver driver)
{
_driver = driver;
}
}
Your steps steps will now have access to a fully instantiated WebDriver object
My tests, which are currently working fine running multithreaded webdriver instances, are using a base step definitions class to hold the driver instance. All step definitions inherit from this, so the driver is available to all steps..
namespace Project.StepDefinitions
{
[Binding]
public class BaseStepDefinitions
{
private const string CurrentPageKey = "Current.Page";
public static IWebDriver Driver { get; set; }
protected LogonPageModel LogonPage
{
get { return (LogonPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
protected RegisterPageModel RegisterPage
{
get { return (RegisterPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
}
}
//////////////
namespace SpecDriver.StepDefinitions
{
[Binding]
public class LoginSteps : BaseStepDefinitions
{
[Given(#"I navigate to the homepage")]
public void GivenINavigateToTheHomepage()
{
Driver.Navigate().GoToUrl(SettingsManager.BaseUrl);
}
}
}
etc etc...
Just create a new separated class with a static property that returns driver:
static class DriverProvider
{
private static IWebDriver _driver;
public static IWebDriver Driver
{
get
{
if (_driver == null)
{
_driver = new ChromeDriver();
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(40);
_driver.Manage().Window.Maximize();
}
return _driver;
}
}
}
Each time you will need to do something with driver, just call it in a such way:
SomeMethod(DriverProvider.Driver);
//
IWebelement e = DriverProvider.Driver.FindElement(By.XPath("you_XPath"));
e.Click();
// etc etc etc
I want easy way to launch Selenium webdriver instance and run various tests on it. I'm trying to do this in Suite file, but it doesn't work. Instance is killed instantly. Is there any alternatives on how to do this?
Potentially I want to add more drivers (IE, Chrome) in this suite and if possible launch separately. Any suggestions welcome.
namespace NUnit.Tests
{
public class AllTests
{
private static IWebDriver _Driver;
[TestFixtureSetUp]
public void SuiteSetUp()
{
_Driver = new FirefoxDriver();
}
[TestFixtureTearDown]
public void SuiteTearDown()
{
try
{
_Driver.Quit();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
}
[Suite]
public static TestSuite Suite
{
get
{
LoginTest lt = new LoginTest { Driver=_Driver };
suite.Add(lt);
AnotherTest at = new AnotherTest { Driver=_Driver };
suite.Add(at);
return suite;
}
}
}
}
I did this in Java, I made a base class, declared the webdriver as static, put my startup/config methods in this class and then extended it in to each test class i made.
Im sure its the same for C#.
Trying to run this with base class / extended classes failed. As webdriver instance didn't get initialized properly and couldn't be killed properly. Instead I created SetupIE(), SetupChrome(), SetupFirefox() methods in Suite and also created teardown method that would work as last test for suite.
Here is the code:
namespace TestNamespace
{
using System;
using NUnit.Framework;
using NUnit.Core;
using SeleniumTests;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
class AllTests
{
public static IWebDriver WebDriver { get; private set; }
[Suite]
public static TestSuite Suite
{
get
{
TestSuite suite = new TestSuite("All Tests");
//Setup a Web driver (see methods below for different browsers) - SetupIE(), SetupChrome(), SetupFirefox()
SetupIE();
// Add tests to suite
suite.Add(new FlashLoadedTest { Driver = WebDriver });
// Tear down a Web driver
suite.Add(new TearDownTest { DriverToTearDown = WebDriver });
// return suite to NUnit
return suite;
}
}
// Method that's initialises FireFox Driver
private static void SetupFireFox()
{
WebDriver = new FirefoxDriver();
}
// Method that's initialises IE Driver
private static void SetupIE()
{
WebDriver = new InternetExplorerDriver();
}
// Can't get this working, but this is how its supposed to work
private static void SetupChrome()
{
WebDriver = new ChromeDriver(#"C:\Users\<user>\AppData\Local\Google\Chrome\Application");
}
// Class with a test that tears down browser instance
[TestFixture]
class TearDownTest
{
public IWebDriver DriverToTearDown;
[Test]
public void TearDownBrowser()
{
if (DriverToTearDown == null)
Assert.Fail("No Browser to Tear Down");
try
{
DriverToTearDown.Close();
DriverToTearDown.Dispose();
}
catch
{
Assert.Fail("Browser failed to tear down");
}
}
}
}
}
I appreciate this is a little late but may prove useful for future readers.
I created a base class containing a firefox driver with the following and it works perfectly for me. You can then simply reference the base class (Driver in this instance) from your derived test class. Worth noting I'm using C# and Nunit.
Code for base class is:
namespace yournamespace
{
public class Driver
{
public IWebDriver driver;
public StringBuilder verificationErrors;
public Driver()
{
driver = new FirefoxDriver(); //replace with required driver
verificationErrors = new StringBuilder();
}
}
}
Then simply called the 'Driver' class from my test class:
[TestFixture]
public class IMSLogin : Driver
{
//.. all the usual bits and bobs!