When I implement cross browser testing with nunit using TestFixture my tests fails when run together, passed when run individually. Exception was throwed when SendKeys method was called because argument was null, but this is not the cause, because when i run this test again test will passed. Ofcourse im tried to debug this issue but i dont find solution. Simple OpenHomePage Test works fine. Here is my code:
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(FirefoxDriver))]
public class TestClass<TWebDriver> where TWebDriver : IWebDriver, new()
{
[OneTimeSetUp]
public void CreateDriver()
{
try
{
PropertiesCollection.driver = new TWebDriver();
Console.WriteLine("Opened browser");
PropertiesCollection.driver.Url = "http://localhost:81/";
Console.WriteLine("Opened URL");
PropertiesCollection.driver.Manage().Window.Maximize();
//initialize test data from excel sheet
ExcelLib.PopulateInCollection(#"c:\users\bolec\documents\visual studio 2015\Projects\RowingSectionTests\RowingSectionTests\TestData.xlsx");
}
catch (Exception msg)
{
Console.WriteLine(msg.ToString());
}
}
[OneTimeTearDown]
public void FixtureTearDown()
{
HomePageObjects homeObj = new HomePageObjects();
homeObj.Logoff();
if (PropertiesCollection.driver != null) PropertiesCollection.driver.Quit();
}
[TearDown]
public void TearDown()
{
//Take screen on failure
if (TestContext.CurrentContext.Result.Outcome.Status.Equals(TestStatus.Failed))
{
string fileName = Regex.Replace(TestContext.CurrentContext.Test.FullName + "_" + DateTime.Now.ToString(), "[^a-z0-9\\-_]+", "_", RegexOptions.IgnoreCase);
((ITakesScreenshot)PropertiesCollection.driver).GetScreenshot().SaveAsFile(#"c:\users\bolec\documents\visual studio 2015\Projects\RowingSectionTests\RowingSectionTests\Screenshots\" + fileName + ".png", System.Drawing.Imaging.ImageFormat.Png);
}
}
//will always passed
[Test]
public void OpenHomePage()
{
HomePageObjects homeObj = new HomePageObjects();
}
//login with correct credentials will login to acc
[Test]
public void Login()
{
HomePageObjects homeObj = new HomePageObjects();
LoginPageObjects loginObj = homeObj.ToLoginPage();
loginObj.Login(ExcelLib.ReadData(1, "UserName"), ExcelLib.ReadData(1, "Password"));
//checking is URL correct after loggin
Assert.AreEqual("http://localhost:81/", PropertiesCollection.driver.Url.ToString());
//checking is login is correct on navbar
Assert.AreEqual(homeObj.GetUserLoginStringInButton().ToLower(), ExcelLib.ReadData(1, "UserName").ToLower());
}
The problem with using the static PropertiesCollection is that any changes to the static class in one test will be reflected in the other test, making the chances or creating a test dependency very high (as you have discovered).
You have two choices, firstly don't use a static instead create an instance. Alternatively, ensure that in a setup and your teardown methods you set/reset your PropertiesCollection back to it's required state.
Using the OneTimeSetUp attribute is also risky as it only runs once for all the tests in your fixture.
Related
I am still learning to use MSTest and Moq for automated unit testing in my application. I have successfully mocked the code and run it. It is showing that the tests are passed , but the code coverage is 0%. This is my code below.What needs to be changed so that code coverage becomes 100%.
I know this question has been asked a couple of times before, but nothing seems to help me.So can anyone suggest me what am I doing wrong.
Any help is highly appreciated.Thanks.
PS: I'm using Sonarcube for knowing the code coverage.
using Moq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;
using System.Diagnostics.CodeAnalysis;
namespace MyNameSpace
{
[TestClass]
public class ApplicationTest
{
readonly Helper moqHelper = new Helper();
[TestMethod()]
public void GetDataFromDataBaseMoq()
{
Task<bool> returnValue;
Mock<Application> mockType = new Mock<Application>();
mockType.CallBase = true;
mockType.Setup(x => x.GetDataFromDataBase()).Returns(returnValue = moqHelper.GetDataFromDataBaseMoq());
if (returnValue.Result)
{
Assert.IsTrue(true);
}
else
{
Assert.Fail();
}
}
}
[ExcludeFromCodeCoverage]
class Helper
{
internal async Task<bool> GetDataFromDataBaseMoq()
{
bool returnValue = true;
return returnValue;
}
}
public class Application : IApplication
{
public virtual async Task<bool> GetDataFromDataBase()
{
//if data retrive successfull, return true, else false
return true;
}
}
public interface IApplication
{
Task<bool> GetDataFromDataBase();
}
}
You're not testing your application code, you're testing your mock. You could've seen this by setting a breakpoint in Application.GetDataFromDataBase() and debugging your test; you'd see it won't be hit.
You need to only mock dependencies, if any. So rewrite your test to actually call into your code:
[TestMethod]
public async Task GetDataFromDataBase_Returns_True()
{
// Arrange
IApplication classUnderTest = new Application();
// Act
var result = await classUnderTest.GetDataFromDataBase();
// Assert
Assert.IsTrue(result);
}
And you'll see the need for all the mocks and helpers goes away.
I got an application with two types of users. Say, we got user
A (password: 1234)
B (password: ABCD)
This is an example for a test:
[TestFixture]
public class TestCalls
{
private static RestApiClient client;
[SetUp]
public void Init()
{
client = new RestApiClient("http://localhost:1234/");
SetToken("A", "1234");
}
[Test]
public async Task ExampleTest()
{
// a test methods
var value = await client.ExecuteRequestAsync(...);
Assert.That(value, Is.Not.Null.And.Not.Empty)
// more assertions
}
}
SetToken simply sets the authentication-token on my RestApiClient-insance.
The problem is that user A gets other values than user B (same type of course, different values, but another database)
I could solve it with using TestCaseAttribute but I want to have the SetToken in SetUpAttribute-method Init()
[Test]
[TestCase("A")]
[TestCase("B")]
public async Task ExampleTest(string user)
{
SetToken(user, "1234"); // of course setting right password
// a test methods
var value = await client.ExecuteRequestAsync(...);
Assert.That(value, Is.Not.Null.And.Not.Empty)
// more assertions
}
Is there any possibility to have s.th like configurations for NUnit? So I could run everything twice (for both users)?
Or what could I do to test both users?
(Copy-pasting all tests is not a solution)
Found the solution:
We can add multiple TestFixture-attributes and give them values.
We need to define a constructor for the test-class with the same amount of arguments.
Then in the constructor we assign those values to fields (here I'm using private readonly fields)
And then we can use them in the SetUp.
NUnit automatically creates now test-cases for both users.
my Test-class looks like this now:
[TestFixture("A", "1234")]
[TestFixture("B", "ABCD")]
public class TestCalls
{
private static RestApiClient client;
private readonly string username;
private readonly string password;
public TestCalls(string username, string password)
{
this.username = username;
this.password = password;
}
[SetUp]
public void Init()
{
client = new RestApiClient("http://localhost:1234/");
SetToken(this.username, this.password);
}
[Test]
public async Task ExampleTest()
{
// a test methods
var value = await client.ExecuteRequestAsync(...);
Assert.That(value, Is.Not.Null.And.Not.Empty)
// more assertions
}
}
I'm writing integration tests using the MSTest framework. The tests and code under test all have significant logging built into them.
I'm trying to figure out a way to hook into the Assert's output so I can write it to the log files along with the rest of log.
For example, if I have a test method like
[TestMethod]
SomeRandomIntegrationTest()
{
//Code to actually run the test, and includes logging.
Assert.AreEqual(true, false, "This error message should also appear in the log");
}
I would get
Message: Assert.AreEqual failed. Expected true. Got false. This error message should also appear in the log.
in my log file.
I tried doing
private StringBuilder testOutputBuilder;
private StringWriter testOutputWriter;
private TextWriter originalWriter;
[TestInitialize]
public virtual void Initialize()
{
//Redirect the test output into the log files
testOutputBuilder = new StringBuilder();
testOutputWriter = new StringWriter(testOutputBuilder);
originalWriter = Console.Out;
Console.SetOut(testOutputWriter);
}
[TestCleanup]
public virtual void TestCleanup()
{
if (TestContext.CurrentTestOutcome != UnitTestOutcome.Passed)
{
//File logging happens here using the testOutputBuilder
}
Console.SetOut(originalWriter);
testOutputWriter.Dispose();
}
but the testOutputBuilder returns an empty string.
How can I grab the string outputs from the assert methods in MSTest?
I wrote a workaround using separate function:
public string WriteErrorToFile(TextWriter textwriter, string errorMessage)
{
textwriter.WriteLine(errorMessage);
return errorMessage;
}
and code inside test should be modified like:
Assert.AreEqual(true, false, WriteErrorToFile(originalWriter, "This error message should also appear in the log"));
If you have only one log file then you can remove first parameter to the function.
Hope this helps
I did this:
public void OutputAssert(Action func)
{
try
{
func();
}
catch (Exception ex)
{
OutputToFile(ex.Message);
throw ex;
}
}
And then in the test:
[TestMethod]
public void TestAssertOutput()
{
OutputAssert(() => Assert.AreEqual(false, true, "test message"));
}
The output being:
Assert.AreEqual failed. Expected:<False>. Actual:<True>. test message
I have a method that creates 2 remote web drivers. one with chrome and another with firefox:
Driver.cs
public class Driver
{
public static IWebDriver Instance { get; set; }
public static void Initialize()
{
DesiredCapabilities[] browsers = {DesiredCapabilities.Firefox(),DesiredCapabilities.Chrome()};
foreach (DesiredCapabilities browser in browsers)
{
if (browser == DesiredCapabilities.Chrome())
{
var browser = DesiredCapabilities.Chrome();
System.Environment.SetEnvironmentVariable("webdriver.chrome.driver", "C:/Users/jm/Documents/Visual Studio 2013/Projects/VNextAutomation - Copy - Copy (3)/packages/WebDriverChromeDriver.2.10/tools/chromedriver.exe");
ChromeOptions options = new ChromeOptions() { BinaryLocation = "C:/Users/jm/AppData/Local/Google/Chrome/Application/chrome.exe" };
browser.SetCapability(ChromeOptions.Capability, options);
Console.Write("Testing in Browser: " + browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
} else {
Console.Write("Testing in Browser: "+ browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
}
}
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
}
Then I have a Test class:
[TestClass]
public class LoginTests
{
[TestInitialize]
public void Init()
{
Driver.Initialize();
}
[TestMethod]
public void Failed_login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(LoginFail.IsAt, "Login failure is incorrect");
}
[TestMethod]
public void Admin_User_Can_Login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(HomePage.IsAt, "Failed to login.");
}
[TestCleanup]
public void Cleanup()
{
Driver.Close();
}
}
}
The problem is when Driver.Intialize gets called it doesn't run both chrome and firefox. What I want to happen is that when the Init method gets called it starts both browsers and runs the Test Methods in each browser.
The way I am currently doing this is with NUnit.
I had the same problem and could not find a good way to do it with MSTest.
What I am doing would be:
As you can see I just create a new TestFixture for each browser.
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
[TestFixture(typeof(FirefoxDriver))]
public class LoginTests<TWebDriver> where TWebDriver : IWebDriver, new()
{
[SetUp]
public void Init()
{
Driver.Initialize<TWebDriver>();
}
[Test]
public void Failed_login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(LoginFail.IsAt, "Login failure is incorrect");
}
[Test]
public void Admin_User_Can_Login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(HomePage.IsAt, "Failed to login.");
}
[TearDown]
public void Cleanup()
{
Driver.Close();
}
}
}
Driver Class
public class Driver<TWebDriver> where TWebDriver : IWebDriver, new()
{
public static IWebDriver Instance { get; set; }
public static void Initialize()
{
if (typeof(TWebDriver) == typeof(ChromeDriver))
{
var browser = DesiredCapabilities.Chrome();
System.Environment.SetEnvironmentVariable("webdriver.chrome.driver", "C:/Users/jm/Documents/Visual Studio 2013/Projects/VNextAutomation - Copy - Copy (3)/packages/WebDriverChromeDriver.2.10/tools/chromedriver.exe");
ChromeOptions options = new ChromeOptions() { BinaryLocation = "C:/Users/jm/AppData/Local/Google/Chrome/Application/chrome.exe" };
browser.SetCapability(ChromeOptions.Capability, options);
Console.Write("Testing in Browser: " + browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
} else {
Console.Write("Testing in Browser: "+ browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
}
}
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
}
}
I have tried to fit it around your code.
If you wanted to be able to specify a browser to run a test on an adhoc basis rather than all of them every time using TestFixtures, Richard Bradshaw has an excellent tutorial here.
The idea is to use an app config file (and Factory Pattern) that houses values such as the browser, version, platform, selenium hub and port information (as well as any other data you might require in your Hub/Node implementation on Grid) and pull it in at the time of testing to create a WebDriver instance. You can then modify this file in between tests to spin up a WebDriver of a different type if necessary.
We use this to run tests sequentially with NUnit and it has proven quite effective.
an easier and a little bit more straight forward solution using NUnit:
namespace Test
{
//add all browser you want to test here
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
public class SkillTest<TWebDriver> where TWebDriver : IWebDriver, new()
{
private IWebDriver _driver;
private string driverPath;
[SetUp]
public void Init()
{
_driver = new TWebDriver();
_driver.Navigate().GoToUrl("https://localhost:5001/");
}
[Test]
public void your_test_case()
{
//some test logic
}
[TearDown]
public void CleanUp()
{
_driver.Quit();
_driver.Dispose();
}
}
}
I have a test class Navigation and I have derived class LeadExTest that is derived from Navigation class. Both class are of [TestClass] type
Now i have a ordered test file, that has a few tests i need to be executed in the order i have shown below.
AdminLogin
do some action
quit browser
AdminLogin, Navigate to page and quit browser test methods belong to Navigation class and do some action belongs to leadextest class
When i execute this ordered test file, admin login and do some action test cases execute just fine, but quit browser method is not getting hit.
//Base class
public class Navigation
{
protected static IWebDriver driver;
protected WebDriverWait wait;
protected StringBuilder verificationErrors;
private string baseURL;
//private bool acceptNextAlert = true;
protected static string advertiserId = "6570";
protected static Actions builder;
[TestInitialize]
public void SetupTest()
{
if (driver == null)
{
driver = new FirefoxDriver();
driver.Manage().Window.Maximize();
baseURL = ConfigurationManager.AppSettings["base_url"].ToString();
verificationErrors = new StringBuilder();
//string url = #"https://stage.madisonlogic.com/login.aspx";
//driver.Navigate().GoToUrl(url.ToString());
driver.Navigate().GoToUrl(ConfigurationManager.AppSettings["test_url"].ToString());
builder = new Actions(driver);
}
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
}
[TestMethod]
public void adminLogin()
{
CommonFunctions.Login(driver, "rlodha", "a");
if (IsElementPresent(By.ClassName("TopTitle")))
Assert.AreEqual("Admin Center | Dashboard", driver.FindElement(By.ClassName("TopTitle")).Text.Trim().ToString());
else
Assert.Fail("Timed Out");
}
[TestMethod]
public void browserQuit()
{
CommonFunctions.BrowserQuit(driver);
Assert.IsNull(driver);
}
//derived class
[TestMethod]
public void Nav_Lead_Delivery()
{
builder.MoveToElement(driver.FindElement(By.Id("Content_AdvertiserMenu1_LeadsBtn"))).Perform();
driver.FindElement(By.Id("Content_AdvertiserMenu1_LeadExportBtn")).Click();
Console.Write("Hi");
}
Well you are just declaring it as another test method, so of course this isn't going to work.
You need to give MSTest much more of a clue about when to call your method, so replace it with a ClassCleanup to tell MSTest to call this method when all the tests are done.