Selenium Webdriver C# - Running more than one test case in VS 2017 from Test Suite - selenium-webdriver

I have been working on Page Object Framework which will have categorized test suites depending on the page. I have followed all steps in order to build a decent framework.
My each Unit Test, contains one method which follows simple steps. So far I have been able to create a few automated test cases. The issue began when I wanted to run more than one test case from the test suite. I have one chrome web driver instance which is in a separate class. Below is an example:
using System;
using System.Dynamic;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
namespace SystemUiAutomationTestFramework
{
public static class Browser
{
private static readonly IWebDriver _webDriver = new ChromeDriver(Properties.Settings.Default.ChromePathDriver);
public static IWebDriver WebDriver {
get { return _webDriver; }
}
public static ISearchContext Driver
{
get { return _webDriver; }
}
public static string Url
{
get { return _webDriver.Url; }
}
public static string Title
{
get { return _webDriver.Title; }
}
public static void Goto(string url)
{
_webDriver.Manage().Window.Maximize();
_webDriver.Url = url;
}
public static void Close()
{
_webDriver.Quit();
}
}
}
Each test case when it is run is independent and as good practice shows, there should be no test order implementation because it generates flows. I will place two examples which check simple login operation and login validation.
Below you can find a class for the login page:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Support.UI;
namespace SystemUiAutomationTestFramework
{
public class LoginPage
{
static string Url = "http://..";
private static string LoginUrl = "http://...";
private static string PageTitle = "System title page";
private static string LoginPlaceholder = "Login";
private static string PswdPlaceholder = "Password";
private static string ButtonText = "Sign in";
private static string ErrorMessage = "Wrong login or password";
/* LoginPage Elements */
[FindsBy(How = How.Id, Using = "inputLogin")]
private IWebElement inputLogin;
[FindsBy(How = How.Id, Using = "inputPassword")]
private IWebElement inputPassword;
[FindsBy(How = How.TagName, Using = "button")]
private IWebElement loginButton;
[FindsBy(How = How.ClassName, Using = "errorMsg")]
private IWebElement errorMessage;
/*----------------------------------------*/
public void Goto()
{
Browser.Goto(Url);
}
public bool IsAtLoginPage()
{
return Browser.Url == LoginUrl;
}
public bool IsAtLoginPageTitle()
{
return Browser.Title == PageTitle;
}
public bool IsAtLoginField()
{
return inputLogin.GetAttribute("placeholder") == LoginPlaceholder;
}
public bool IsAtPswdField()
{
return inputPassword.GetAttribute("placeholder") == PswdPlaceholder;
}
public bool IsAtLoginButton()
{
return loginButton.Text == ButtonText;
}
public void InputCredentials(string userName, string userPassword)
{
inputLogin.SendKeys(userName);
inputPassword.SendKeys(userPassword);
loginButton.Click();
}
public void WaitErrorMessage()
{
WebDriverWait wait = new WebDriverWait(Browser.WebDriver, TimeSpan.FromSeconds(10));
wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.ClassName("errorMsg")));
}
public bool IsAtErrorMessage()
{
return errorMessage.Text == ErrorMessage;
}
public void ReportPageSuccessLogin()
{
Console.WriteLine("Application Url checked");
Console.WriteLine("Application Title checked");
Console.WriteLine("Login Field present");
Console.WriteLine("Password Field checked");
Console.WriteLine("Sign in button checked");
Console.WriteLine("Login ssuccess");
}
public void ReportPageValidationTest()
{
ReportPageSuccessLogin();
Console.WriteLine("Fake Credentials entered");
Console.WriteLine("Login Button Pressed");
Console.WriteLine("Login or Password validation message displayed: " + errorMessage.Displayed);
}
}
}
I also have an API class for Pagefactoring. As an example:
public static class Pages
{
public static LoginPage LoginPage
{
get
{
var loginPage = new LoginPage();
PageFactory.InitElements(Browser.Driver, loginPage);
return loginPage;
}
}
Now for the test cases, below an example when a user is on the login page, all elements are displaed, logs into the system, system checks if the user has logged into and closes the instance.
using System;
using System.Runtime.Remoting.Channels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SystemUiAutomationTestFramework;
namespace TestSuite.LoginPage
{
[TestClass]
public class LoginPageTest
{
[TestMethod]
public void Can_Go_LoginPage()
{
Pages.LoginPage.Goto();
Assert.IsTrue(Pages.LoginPage.IsAtLoginPage());
Assert.IsTrue(Pages.LoginPage.IsAtLoginPageTitle());
Assert.IsTrue(Pages.LoginPage.IsAtLoginField());
Assert.IsTrue(Pages.LoginPage.IsAtPswdField());
Assert.IsTrue(Pages.LoginPage.IsAtLoginButton());
Pages.LoginPage.InputCredentials(SettingsService.Username, SettingsService.Userpassword);
Pages.HomePage.IsAtHomePage();
Pages.LoginPage.ReportPageSuccessLogin();
}
[TestCleanup]
public void CleanUp()
{
Browser.Close();
}
}
}
The other one just validates the login page by providing fake login and password and if the error message is correctly displayed the test case finishes also by closing the instance.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SystemUiAutomationTestFramework;
namespace TestSuite.LoginPage
{
[TestClass]
public class LoginPageValidationTest
{
[TestMethod]
public void Can_Validate_LoginPage()
{
Pages.LoginPage.Goto();
Assert.IsTrue(Pages.LoginPage.IsAtLoginPage());
Assert.IsTrue(Pages.LoginPage.IsAtLoginPageTitle());
Assert.IsTrue(Pages.LoginPage.IsAtLoginField());
Assert.IsTrue(Pages.LoginPage.IsAtPswdField());
Assert.IsTrue(Pages.LoginPage.IsAtLoginButton());
Pages.LoginPage.InputCredentials("abcd.efgh", "test123");
Pages.LoginPage.WaitErrorMessage();
Assert.IsTrue(Pages.LoginPage.IsAtErrorMessage());
Pages.LoginPage.ReportPageValidationTest();
}
[TestCleanup]
public void CleanUp()
{
Browser.Close();
}
}
}
Now the issue happens when I try those two test cases from the Login Page Test Suite, one finishes as passed the other one as failed. From the error message, I understand that it is because the other test case is trying to use an instance of the Webdriver which is already running.
I would like to know your opinion/guides/solution how can I solve this problem. I apologize for the long post but I thought that if I place my code it will be easy for you to understand my issue.
Best regards and thank you for your answers or linking me to the topic which either a duplicate of my issue or there is a solution already for it.

I was able to solve the issue on my own. I have created an
property for my driver class and an Initialize method which is called each time a test class is called. Also refactored my code to be more flexible.

Related

ABPFramwork - Remove api from layer application in swagger

I have created a project using abpframwork. When running swagger, swagger receives the function in the application layer is a api. I don't want that. Can you guys tell me how to remove it in swagger
Code in Application Layer
public class UserService : AdminSSOAppService, ITransientDependency, IValidationEnabled, IUserService
{
IUserRepository _userRepository;
private readonly ILogger<UserService> _log;
public UserService(IUserRepository userRepository,
ILogger<UserService> log
)
{
_userRepository = userRepository;
_log = log;
}
public async Task<List<UserDto>> GetList()
{
var list = await _userRepository.GetListAsync();
return ObjectMapper.Map<List<User>, List<UserDto>>(list);
}
public async Task<UserDto> GetUserById(int Id)
{
var user = await _userRepository.GetAsync(c=>c.Id == Id);
return ObjectMapper.Map<User, UserDto>(user);
}
}
Code in HttpApi Layer
[Area(AdminSSORemoteServiceConsts.ModuleName)]
[RemoteService(Name = AdminSSORemoteServiceConsts.RemoteServiceName)]
[Route("api/user/user-profile")]
public class UserController : ControllerBase, IUserService
{
private readonly IUserService _userAppService;
public UserController(IUserService userAppService)
{
_userAppService = userAppService;
}
[HttpGet]
[Route("get-list-httpapi")]
public Task<List<UserDto>> GetList()
{
return _userAppService.GetList();
}
[HttpGet]
[Route("get-by-id-httpapi")]
public Task<UserDto> GetUserById(int Id)
{
return _userAppService.GetUserById(Id);
}
}
I can suggest a workaround as to enable only the APIs you need to appear on swagger (though the ones that don't appear anymore will still be available for consumption).
I would suggest you add a configuration part in your *.Http.Api project module inside your ConfigureSwaggerServices, like so:
context.Services.AddSwaggerGen(options =>
{
options.DocInclusionPredicate(
(_, apiDesc) =>
apiDesc
.CustomAttributes()
.OfType<IncludeInSwaggerDocAttribute>()
.Any());
});
And for the attribute, it would be very simple, like so:
[AttributeUsage(AttributeTargets.Class)]
public class IncludeInSwaggerDocAttribute : Attribute
{
}
This will let you achieve what you want, however I still recommend reading the doc carefully to be able to implement DDD.

Getting null pointer exception while open the url in selenium automation [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
Here, I am using page object model and I want to pass the driver to other classes.But i am getting null pointer exception while launch the website (driver.get("")).
This is my base class
public class BaseClass {
public WebDriver driver;
public Logger logger = Logger.getLogger(Common.class.getPackage().getName());
public void startBrowser() {
if(driver == null) {
System.setProperty("webdriver.chrome.driver", "desktop/chromedriver.exe");
driver = new ChromeDriver();
}
}
public void quitBrowser() {
driver.quit();
}
}
and then this is my runner class:
public class TestRunnerTestNG extends AbstractTestNGCucumberTests {
BaseClass a;
#BeforeClass
public void launch()
{
a = new BaseClass();
a.startBrowser();
}
#AfterClass
public void tearBrowser()
{
a.quitBrowser();
}
}
Here, I am starting the browser using Beforeclass annotation and quit the browser using afterClass annotation.
and the following class is my page Object class: and here I have the method for launch the url:
public class SignIn extends BaseClass {
public SignIn(WebDriver driver) {
this.driver = driver ;
PageFactory.initElements(driver, this);
}
//Locators
#FindBy(id = "email")
private WebElement user_Email;
#FindBy(id = "password")
private WebElement user_Password;
#FindBy(xpath = "//span[text()='Sign In']")
private WebElement signIn_Btn;
public void landing()
{
driver.get("https://***************"); <<<< Here I am getting the null pointer exception.
}
public void signInPageGUI()
{
boolean checkSignInTextGUI = waitElement(signInText);
Assert.assertTrue(checkSignInTextGUI);
boolean CheckEmailField = waitElement(user_Email);
Assert.assertTrue(CheckEmailField);
boolean checkPwdField = waitElement(user_Password);
Assert.assertTrue(checkPwdField);
}
private void emailField(String emailName) {
user_Email.sendKeys(emailName);
}
private void passwordField(String password) {
user_Password.sendKeys(password);
}
}
and the final code is my step definition class and this is place I am calling the code.
public class LoginPage {
WebDriver driver ;
#Given("user landed to the yoco URL {string}")
public void landedOnYoCo(String string) {
System.out.println("print the string" +string);
System.out.println("driver value is " );
SignIn logIN = new SignIn(driver);
logIN.landing();
}
}
Here, Only I am calling the landing method to launch the website.
and The error is:
java.lang.NullPointerException
at pageObject.SignIn.landing(SignIn.java:83)
at stepDefs.LoginPage.landedOnYoCo(LoginPage.java:32)
at ✽.user landed to the yoco URL "https://my.yocoboard.com"(file:///Users/vinoth/Git/YoCoAutomation/src/test/resources/logIN.feature:7)
Call startBrowser before calling landing to initialize driver.
public void landedOnYoCo(String string) {
System.out.println("print the string" +string);
System.out.println("driver value is " );
SignIn logIN = new SignIn(driver);
logIN.startBrowser();
logIN.landing();
}

Nancy fx how to use in Windows Forms

Here I have a simple WinForm app which has a NancyFx service all working fine: I use a Person object which implements the IPerson interface. The nancyModule has a ctor with a parameter of IPerson and in the post route of the nancyModule I use the this.Bind(); If I want to display the person on the form how do I do it?
using System;
using System.Windows.Forms;
using Microsoft.Owin.Hosting;
using Nancy;
using Nancy.ModelBinding;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private IDisposable dispose;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string uri = "http://localhost:8080/";
dispose = WebApp.Start<Startup1>(uri);
}
}
public interface IPerson
{
String Name { get; set; }
}
public class Person : IPerson
{
public String Name { get; set; }
}
public class nancyModule : NancyModule
{
public nancyModule(IPerson person)
{
Post["/data"] = _ =>
{
person = this.Bind<Person>();
//HOW DO I DISPLAY THE person ON THE FORM UI
return HttpStatusCode.OK;
};
}
}
}
If you want to display the person data on the form then you need to call your REST API from your Win Forms application. Grab the response and output the results. Simply put, this is how you can achieve this.
I haven't used async and await keywords which ideally you would but
for brevity I have omitted this.
Firstly, I removed the dependency of IPerson from your module as this isn't a dependency as such but an output from your POST. With that minor adjustment, it looks like this:
If you still feel strongly about IPerson being a dependency then simply leave it and the code will still work as expected.
public class PersonModule : NancyModule
{
public PersonModule()
{
this.Post["/data"] = args => this.AddPerson();
}
private Negotiator AddPerson()
{
var person = this.Bind<Person>();
return this.Negotiate
.WithStatusCode(HttpStatusCode.Created)
.WithContentType("application/json")
.WithModel(person);
}
}
Now from your Win Forms application simply call the API via the HttpClient, like this:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var person = new Person { Name = "Foo Bar" };
var serializer = new JavaScriptSerializer();
var response = client.PostAsync(
"http://localhost:8080/data",
new StringContent(serializer.Serialize(person), Encoding.UTF8, "application/json")).Result;
var result = new JavaScriptSerializer().Deserialize<Person>(response.Content.ReadAsStringAsync().Result);
TextBox1.Text = result.Forename;
}
Purest's out there will mention 3rd party libraries such as Json.NET
and Service Stack which allows for easier serialization and
deserialization but again for simplicity in this example I am using
out of the box features.

testng how to dynamically set groups from Factory?

Before I setup a test class like the code below:
1. the Factory and test Dataprovider both used excel as the dataprovider.
2. In the Factory dataprovider table, it has a list of url
3. Each time, it will find one of the url in the factory dataprovider table, and run the test in each test methods..
public class Test {
WebDriver driver;
private String hostName;
private String url;
#Factory(dataProvider = "xxxx global variables", dataProviderClass = xxxx.class)
public GetVariables(String hostName, String url) {
this.hostName = hostName;
this.url = url;
}
#BeforeMethod
#Parameters("browser")
public void start(String browser) throws Exception {
driver = new FirefoxDriver();
driver.get(url);
Thread.sleep(1000);
}
#Test(priority = 10, dataProvider = "dataprovider Test A", dataProviderClass = xxx.class)
public void TestA(Variable1,
Variable2,Variable3) throws Exception {
some test here...
}
#Test(priority = 20, dataProvider = "dataprovider Test B", dataProviderClass = xxx.class)
public void TestB(Variable1,
Variable2,Variable3)
throws Exception {
some test here...
}
#AfterMethod
public void tearDown() {
driver.quit();
}
Now I want to dynamically assign different group for each test for different url. I am thinking add a variable 'flag' in the #Factory dataprovider:
#Factory(dataProvider = "xxxx global variables", dataProviderClass = xxxx.class)
public GetVariables(String hostName, String url, String flag) {
this.hostName = hostName;
this.url = url;
this.flag = flag;
}
That when flag.equals("A"), it will only run test cases in test groups={"A"}.
When flag.equals("B"), it will only run test cases in test groups ={"B"},
When flag.equals("A,B"), it will only run test cases in test groups ={"A","B"}
Is there any way I can do that?
Thank you!
TestNG groups provides "flexibility in how you partition your tests" but it isn't for conditional test sets. For that you simply use plain old Java.
You can use inheritance or composition (I recommend the latter, see Item 16: Favor composition over inheritance from Effective Java).
Either way the general idea is the same: use a Factory to create your test class instances dynamically creating the appropriate class type with the appropriate test annotations and/or methods that you want to run.
Examples:
Inheritance
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class DemoTest {
#Factory
public static Object[] createTests() {
return new Object[]{
new FlavorATest(),
new FlavorBTest(),
new FlavorABTest()
};
}
/**
* Base test class with code for both A-tests and B-tests.
*
* Note that none of these test methods are annotated as tests so that
* subclasses may pick which ones to annotate.
*/
public static abstract class BaseTest {
protected void testA() {
// test something specific to flavor A
}
protected void testB() {
// test something specific to flavor B
}
}
// extend base but only annotate A-tests
public static class FlavorATest extends BaseTest {
#Test
#Override
public void testA() {
super.testA();
}
}
// extend base but only annotate B-tests
public static class FlavorBTest extends BaseTest {
#Test
#Override
public void testB() {
super.testB();
}
}
// extend base and annotate both A-tests and B-tests
public static class FlavorABTest extends BaseTest {
#Test
#Override
public void testA() {
super.testA();
}
#Test
#Override
public void testB() {
super.testB();
}
}
}
Composition
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class DemoTest {
#Factory
public static Object[] createTests() {
return new Object[]{
new FlavorATest(),
new FlavorBTest(),
new FlavorABTest()
};
}
private static void testA() {
// test something specific to flavor A
}
private static void testB() {
// test something specific to flavor B
}
// only create A-test methods and delegate to shared code above
public static class FlavorATest {
#Test
public void testA() {
DemoTest.testA();
}
}
// only create B-test methods and delegate to shared code above
public static class FlavorBTest {
#Test
public void testB() {
DemoTest.testB();
}
}
// create A-test and B-test methods and delegate to shared code above
public static class FlavorABTest {
#Test
public void testA() {
DemoTest.testA();
}
#Test
public void testB() {
DemoTest.testB();
}
}
}
Your factory methods won't be as simple as you'll need to use your "flag" from your test data to switch off of and create instances of the appropriate test classes.

how to use selenium with fitnesse

I am creating a small test. In Code behind I have two classes. Pages, LoginPage.
The first part is running. I dont know how to integrate with second part. Currently I am able to open the browser. Also I am trying to use the Page obect model pattern .
Fitnesse code
!|import|
|TestFramework|
!|script|Pages|
|Goto||https://gmail.com|
|LoginPage|CheckRequiredElementsPresent|Pass|
Fixtures
public class Pages
{
string url;
private LoginPage loginPage;
public static void Goto(string url)
{
Browser.Goto(url);
}
}
public class LoginPage
{
static string PageTitle;
[FindsBy(How = How.Id, Using = "TextUsername")]
private static IWebElement username;
[FindsBy(How = How.Id, Using = "TextPassword")]
private static IWebElement password;
[FindsBy(How = How.Id, Using = "_ButtonLogin")]
private static IWebElement submit;
public string IsAtLoginPage()
{
return "";
}
public string CheckRequiredElementsPresent()
{
if (username != null && password != null && submit != null)
{
return "Pass";
}
return "Fail";
}
}
}
You need to do something like below:
Fitnesse Code
!|import|
|TestFramework|
!|script|Pages|
|Goto||https://gmail.com|
|check Required Element|Pass|
You need to call your second class from your Pages class, please see the code changes & fitnesse fixture changes that I've made.
Fixtures
public class Pages
{
string url;
private LoginPage loginPage;
public static void Goto(string url)
{
Browser.Goto(url);
}
// This is what you need to do to refer method of second class.
// This method will be called after Goto method in sequence.
public boolean checkRequiredElement(){
return loginPage.CheckRequiredElementsPresent()
}
}

Resources