I open a page and at the end of the test attempt to close it by calling my CelanUp() in a finally block but sometimes IEDriverServer and the browser are left open. There are no open popups when this happens.
public void CelanUp ()
{
string dialogResponse = string.Empty;
if (m_Driver != null)
{
//Dismiss all dialogs:
dialogResponse = CloseLogonDialog();
dialogResponse = CloseConfirmDialog();
m_Driver.Quit();
m_Driver = null;
}
if (dialogResponse != string.Empty)
{
throw new ApplicationException(dialogResponse);
}
}
What else can I do the close the browser and IEDriverServer?
Edit:
because Selenium's Quit is letting me down by leaving windows open i have looked at other solutions:
try
{
foreach (Process proc in Process.GetProcessesByName("IEDriverServer.exe"))
{
proc.Kill();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Depending on what unit testing software you're using, instead of doing the logic like this, i'd recommend delegating the browser to the unit testing framework.
Put the cleanup method in an After method. as in, After each test... do this.
In java, using jUnit, it'd be written like this.
#After
public void cleanUp() {
driver.quit();
}
This means, after each test, call driver.quit()
Related
I apologize if I come across naïve, I am new to Selenium and still learning.
We are attempting to run these selenium tests on a designated machine via IIS.
When I run the code locally, everything works perfectly. When I publish it to our machine, two instances of chromedriver will show up in the taskmanager when it is only being run once. Sometimes it will close one of the instances, while other times it doesn't close either. Sometimes it will even close both instances and work just fine. I can not figure out why it's being so inconsistent.
Here is a screen shot of the task manager after starting the code.
Any suggestions on this is welcome, below is the code I am running.
private IWebDriver _driver;
[Route("/Test_SignIn")]
public IActionResult Test_SignIn(string environment = "development")
{
string response = "Failed";
try
{
string outPutDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
_driver = new ChromeDriver(outPutDirectory);
if (environment == "production")
{
_driver.Navigate().GoToUrl(productionUrl);
}
else
{
_driver.Navigate().GoToUrl(developmentUrl);
}
By userNameFieldLocator = By.Id("AccountUserName");
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(30));
wait.Until(ExpectedConditions.ElementIsVisible(userNameFieldLocator));
_waitForLoaderToFinish();
IWebElement userNameField = _driver.FindElement(userNameFieldLocator);
IWebElement passwordField = _driver.FindElement(By.Id("AccountPassword"));
IWebElement signInButton = _driver.FindElement(By.XPath("//button[contains(text(), 'Sign In')]"));
userNameField.SendKeys(_username);
passwordField.SendKeys(_password);
signInButton.Click();
By dashboardLocator = By.Id("portalBanner_EmployeeName");
wait.Until(ExpectedConditions.ElementIsVisible(dashboardLocator));
IWebElement dashboard = _driver.FindElement(dashboardLocator);
response = "Success";
}
catch (Exception ex)
{
response = ex.Message;
}
_driver.Close();
_driver.Quit();
return Json(response);
}
private string _waitForLoaderToFinish()
{
try
{
new WebDriverWait(_driver, TimeSpan.FromSeconds(30)).Until(ExpectedConditions.InvisibilityOfElementLocated(By.Id("loader-wrapper")));
return null;
}
catch (TimeoutException e)
{
return $"{e.Message}";
}
}
ChromeDriver (and all other web drivers) are "disposable" objects in .NET. They implement the IDisposable interface. Objects that implement this interface require special handling in order to clean up after they are finished. Typically you see these objects initialized in a using(...) block, similar to below:
using (IWebDriver driver = new ChromeDriver(...))
{
// Use driver
}
Reference: C# Using Statement.
I see that you are closing and quitting the browser, but you need to call _driver.Dispose(); as well. The quick and easy way to accomplish this in your code is to call Dispose() after calling Quit():
_driver.Close();
_driver.Quit();
_driver.Dispose(); // <-- this kills Chrome.exe
return Json(response);
Or modify the method to wrap the use of _driver in a using(...) statement:
[Route("/Test_SignIn")]
public IActionResult Test_SignIn(string environment = "development")
{
string response = "Failed";
try
{
string outPutDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
// Your web driver is a LOCAL variable now, beware!
using (IWebDriver driver = new ChromeDriver(outPutDirectory))
{
if (environment == "production")
{
driver.Navigate().GoToUrl(productionUrl);
}
else
{
driver.Navigate().GoToUrl(developmentUrl);
}
By userNameFieldLocator = By.Id("AccountUserName");
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(ExpectedConditions.ElementIsVisible(userNameFieldLocator));
_waitForLoaderToFinish();
IWebElement userNameField = driver.FindElement(userNameFieldLocator);
IWebElement passwordField = driver.FindElement(By.Id("AccountPassword"));
IWebElement signInButton = driver.FindElement(By.XPath("//button[contains(text(), 'Sign In')]"));
userNameField.SendKeys(_username);
passwordField.SendKeys(_password);
signInButton.Click();
By dashboardLocator = By.Id("portalBanner_EmployeeName");
wait.Until(ExpectedConditions.ElementIsVisible(dashboardLocator));
IWebElement dashboard = driver.FindElement(dashboardLocator);
response = "Success";
}
}
catch (Exception ex)
{
response = ex.Message;
}
return Json(response);
}
Please note that your web driver becomes a local variable now. It should not be a field on the class in order to prevent other methods from accessing this disposable resource.
Does any of you know possible solution for taking screenshots on test failures and exceptions?
I've added following code in TearDown() but as a result it also makes screenshots on passed tests, so it is not the best solution:
DateTime time = DateTime.Now;
string dateToday = "_date_" + time.ToString("yyyy-MM-dd") + "_time_" + time.ToString("HH-mm-ss");
Screenshot screenshot = ((ITakesScreenshot)driver).GetScreenshot();
screenshot.SaveAsFile((settings.filePathForScreenShots + "Exception" + dateToday + ".png"), System.Drawing.Imaging.ImageFormat.Png);
I've already found that idea: http://yizeng.me/2014/02/08/take-a-screenshot-on-exception-with-selenium-csharp-eventfiringwebdriver/, to use WebDriverExceptionEventArgs, but for some reasons it makes also some random screenshots without any reasonable explanation.
Other ideas I found are for Java and not for NUnit which I use with Selenium, so they are pretty useless.
If you put the screenshot logic in your TearDown method it will be called after each test finishes, no matter if it succeeded or failed.
I use a base class that has a function which wraps the tests and catches all exceptions. When a test fails the exception is caught and a screenshot is taken.
I use this base class for all my Selenium tests and it looks something like this:
public class PageTestBase
{
protected IWebDriver Driver;
protected void UITest(Action action)
{
try
{
action();
}
catch (Exception ex)
{
var screenshot = Driver.TakeScreenshot();
var filePath = "<some appropriate file path goes here>";
screenshot.SaveAsFile(filePath, ImageFormat.Png);
// This would be a good place to log the exception message and
// save together with the screenshot
throw;
}
}
}
The test classes then look like this:
[TestFixture]
public class FooBarTests : PageTestBase
{
// Make sure to initialize the driver in the constructor or SetUp method,
// depending on your preferences
[Test]
public void Some_test_name_goes_here()
{
UITest(() =>
{
// Do your test steps here, including asserts etc.
// Any exceptions will be caught by the base class
// and screenshots will be taken
});
}
[TearDown]
public void TearDown()
{
// Close and dispose the driver
}
}
In C# I use NUnit 3.4. This offeres the OneTimeTearDown method that is able to access the TestContext including the state of the previous executed test. Do not use TearDown because it is not executed after a test fails ;)
using OpenQA.Selenium;
using System.Drawing.Imaging;
...
[OneTimeTearDown]
public void OneTimeTearDown()
{
if (TestContext.CurrentContext.Result.Outcome != ResultState.Success)
{
var screenshot = ((ITakesScreenshot)driver).GetScreenshot();
screenshot.SaveAsFile(#"C:\TEMP\Screenshot.jpg", ImageFormat.Jpeg);
}
}
For greater justice here is the code for the MSTest
public TestContext TestContext { get; set; }
[TestCleanup]
public void TestCleanup()
{
if (TestContext.CurrentTestOutcome == UnitTestOutcome.Failed)
{
var screenshotPath = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss.fffff}.png";
MyDriverInstance.TakeScreenshot().SaveAsFile(screenshotPath);
TestContext.AddResultFile(screenshotPath);
}
}
YOu can achieve this easily in TestNG suite FIle
Create a ScreenShot method like Below
public static void CaptureDesktop (String imgpath)
{
try
{
Robot robot = new Robot();
Dimension screensize=Toolkit.getDefaultToolkit().getScreenSize();
Rectangle screenRect = new Rectangle(screensize);
BufferedImage screenshot = robot.createScreenCapture(screenRect);
//RenderedImage screenshot = robot.createScreenCapture(screenRect);
ImageIO.write(screenshot, "png" , new File(imgpath));
}
In above method i used robot class so that you can take screen shot of Dekstop also(window+WebPage) and you can call this method in different Listener class which will implements ITestListener Interface. call your screen Shot method in OntestFailure() of that Listener Class
#Override
public void onTestFailure(ITestResult arg0) {
String methodname = arg0.getMethod().getMethodName();
String imgpath = "./Screenshot/"+methodname+".jpg";
Guru99TakeScreenshot.CaptureDesktop(imgpath);
}
This code is working for me. But this code is written in JAVA. I hope this will work in C# if not i wish this code can help you
Customizing a bit of ExtentReport can give extremely useful report having exception+screenshot captured exactly at time of test failure . Screenshot can be placed alongside exception which user can use to know what was website doing when error occurred.
Report Example
Test
#Test (enabled=true)
public void verifySearch() {
extentlogger = extent.createTest("To verify verifySearch");
//Your other code here.....
soft.assertEquals("xxx", "xxxx");
soft.assertAll();
}
AfterMethod
#AfterMethod
public void getResult(ITestResult result) throws Exception{
if(result.getStatus() == ITestResult.FAILURE)
{
extentlogger.log(Status.FAIL, MarkupHelper.createLabel(result.getThrowable() + " - Test Case Failed", ExtentColor.RED));
try {
// get path of captured screenshot using custom failedTCTakeScreenshot method
String screenshotPath = failedTCTakeScreenshot( result);
extentlogger.fail("Test Case Failed Snapshot is below " + extentlogger.addScreenCaptureFromPath(screenshotPath));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Extension to Andrey Stukalin solution.
If you are using SpecFlow 3.0,
if(TestContext.CurrentTestOutcome == UnitTestOutcome.Failed)
doesn't work anymore.
Have to use
if (scenarioContext.TestError != null)
To explain the title.. Selenium RC keeps insisting that
A system shutdown has already been scheduled
and refusing to conduct automated tests because of this.. I can understand the logic here, I mean you're not going to do your homework if you thought the world would end with a nuclear holocaust...
However.. this is not the Cold War and when I inspect several basic things (such as using shutdown \a, completing a full restart) I find that this is actually not the case!
How can I convince selenium that the world is not going to end and that it should probably do the work I'm telling it to?
N.B. Here, selenium has "refused" to initialise any instance of IE, and will continue to hang until it times out, regardless of clicking Yes or No. I'm using NUnit, c#/.net4.0 to control the tests.
To fix this I replaced the default "runSeleniumTest" function with the below patched version as a user extension:
function runSeleniumTest() {
runOptions = new RemoteRunnerOptions();
var testAppWindow;
if (runOptions.isMultiWindowMode()) {
try{
testAppWindow = openSeparateApplicationWindow('Blank.html', true);
}
catch (e) {
window.onunload = function () { };
window.location.reload();
return;
}
} else if (sel$('selenium_myiframe') != null) {
var myiframe = sel$('selenium_myiframe');
if (myiframe) {
testAppWindow = myiframe.contentWindow;
}
}
else {
proxyInjectionMode = true;
testAppWindow = window;
}
selenium = Selenium.createForWindow(testAppWindow, proxyInjectionMode);
if (runOptions.getBaseUrl()) {
selenium.browserbot.baseUrl = runOptions.getBaseUrl();
}
if (!debugMode) {
debugMode = runOptions.isDebugMode();
}
if (proxyInjectionMode) {
LOG.logHook = logToRc;
selenium.browserbot._modifyWindow(testAppWindow);
}
else if (debugMode) {
LOG.logHook = logToRc;
}
window.selenium = selenium;
commandFactory = new CommandHandlerFactory();
commandFactory.registerAll(selenium);
currentTest = new RemoteRunner(commandFactory);
var doContinue = runOptions.getContinue();
if (doContinue != null) postResult = "OK";
currentTest.start();
}
I found that the "a system shutdown has already been scheduled" error occurred inside of "openSeparateApplicationWindow". I also found that refreshing the selenium test runner window after the error occurred would "restart" the test without the error. Therefore, I patched the "runSeleniumTest" with the following try catch statement so the test runner window reloads if there's an error in "openSeparateApplicationWindow":
try{
testAppWindow = openSeparateApplicationWindow('Blank.html', true);
}
catch (e) {
window.onunload = function () { };
window.location.reload();
return;
}
I also used my blog post for a more specific example of selenium user extensions
Selenium isn't doing anything in this case. That's the IE HTA agent (a built-in Windows process) that's preventing you from doing anything. Perhaps rebooting the machine will do the trick? It looks like you may just have a pending Windows update that's scheduled a future reboot.
I'm fairly new at working with Windows services but I found a peculiar incident and I would like some clarification. I have a Windows service written in C# which I install and start using the command line (great instructions found on stackoverflow). The main method of my service looks like this:
static void Main(string[] args)
{
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
else if (args.Length == 1)
{
const string name = "MyServiceName";
Type type = typeof(MyAssembly);
switch (args[0])
{
case "-install":
ServiceUtils.InstallService(name, type);
ServiceUtils.StartService(args, name);
break;
case "-uninstall":
ServiceUtils.StopService(name);
ServiceUtils.UninstallService(name, type);
break;
default:
throw new NotImplementedException();
}
}
}
When I debug, I ALWAYS send one parameter (-install) to the application. Because of this, the first if statement (if (args.Length == 0) is NEVER executed. This is expected and my service is installed and started just fine. However, if I remove that if statement and just leave the if (args.Length == 1) statement, my service installs correctly but it does not start and I get the following error:
Cannot start MyServiceName on computer '.'
My question is: Why is the code in the first if statement needed when it is NEVER executed in my application?
Here is the supporting code for the InstallService and StartService methods (which I got from stackoverflow also):
public static void InstallService(string serviceName, Type t)
{
if (IsInstalled(serviceName)) return;
try
{
Assembly a = t.Assembly;
using (AssemblyInstaller installer = GetInstaller(a))
{
IDictionary state = new Hashtable();
try
{
installer.Install(state);
installer.Commit(state);
}
catch
{
try
{
installer.Rollback(state);
}
catch
{ }
throw;
}
}
}
catch
{
throw;
}
}
public static void StartService(string[] args, string serviceName)
{
if (!IsInstalled(serviceName)) return;
Console.WriteLine("Service is installed. Attempting to start service.");
ServiceController sc = new ServiceController();
sc.ServiceName = serviceName;
if (sc.Status == ServiceControllerStatus.Stopped)
{
Console.WriteLine("Starting {0}: ", sc.ServiceName);
try
{
sc.Start(args);
sc.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
the first if statement (if (args.Length == 0) is NEVER executed
That's not correct, it is executed. By ServiceController.Start(). You cannot see this because the service controller starts your EXE again, creating another process. A service process this time, not a console process. One that you don't have a debugger attached to. If you remove that if statement then the service immediately exits after getting started. And the service controller correctly complains about that with the "Cannot start MyServiceName" exception message.
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
is run when the service is started by the Service Controller, as the Service Controller doesn't pass any arguments in to Main().
If you don't do ServiceBase.Run(new MyServiceName()), then your service will not respond to any commands from the Service Controller, and you get errors as the ones you see.
Main() is still the entry point of the application. The process is started as a separate step from starting the service(s) within.
It's actually possible to have multiple services running in the same process, and this way of handling things enables that. That is... not just the same exe program, but actually in the same running process.
In Delphi I could do something like this:
try
if not DoSomething then
Exit;
if not DoSomething2 then
Exit;
if not DoSomething3 then
Exit;
finally
DoSomethingElse;
end;
In other means if method DoSomething results false then the program flow is transffered to the finally block and DoSomething2 and DoSomething3 are not executed.
How to achieve such behaviour in C#?
Thanks in advance.
Edit1:
The below example doesn't compile in VS 2008
Edit2: I am sorry I was to fast and forget the return statement;
XElement OrderStatus(q_order_status Request)
{
XElement Response;
try
{
if (DoSomething() != 0 )
{
return;
}
}
catch(Exception e)
{
// catch some errors and eventually pass the e.Message to the Response
}
finally
{
Response = new XElement("SomeTag", "SomeResponse");
}
return Response;
}
Edit3:
After testing it seems that the easiest way to achieve this is to throw an exception if the result of DoSomething1 is false. I can throw my own execption, write a specific message and pass it to the finally clause.
You really shouldn't be using exception handling constructs for flow control. That said, Exit is comparable to return in C#. As the MSDN Documentation about the [return keyword][1] says:
If the return statement is inside a try block, the finally block, if one exists, will be executed before control returns to the calling method.
In general a finally-block will almost always execute if the corresponding try-block has been reached. There are a few rare situations where it is impossible to guarantee that the finally-block executes, but they are all fatal errors, upon which programs should likely immediately crash.
How your code would look in C#:
try
{
if (!DoSomething())
return;
if (!DoSomething2())
return;
if (!DoSomething3())
return;
}
finally
{
DoSomethingElse();
}
But again, don't do this. try and finally are intended for handling exceptions, not for normal flow control.
Reply to your edit:
In your code return doesn't compile because the return type of the method is XElement and return by itself can only be used when the return type is void. You could use return new XElement("SomeTag", "SomeResponse");, as that is what the finally would be doing anyway, or you could assign Response earlier and do return Response;.
Note though that while the finally always executes, the return Response; that comes after it doesn't execute if the reason went into the finally-block is because you did a return inside the try-block.
Answer to updated question:
The reason you're having trouble doing this in an elegant way, is because you seem to be using a combination of return values and exceptions. You should consider manually raising an exception instead of using return values if the sitation is, well, exceptional.
Assuming there is a good reason for the return values however, I'm thinking it might be clearer to go without a finally block altogether, and to include a return at the end of the try block and also in your catch block. That would save you from passing the exception message in a messy way.
I can't really say what the best solution would be, since your code snippet does not show what Response would be if DoSomething() returns a non-zero value.
Original answer:
It depends a little on what you're trying to accomplish. Are exceptions actually being thrown in any of the methods? Otherwise there is no good reason to use a try-finally pattern. This would be equivalent (though maybe not advisable for readability):
bool doneEverything = DoSomething() && DoSomething2() && DoSomething3();
DoSomethingElse();
If there are exceptions being thrown, and handled at a higher level, I'd recommend isolating this code in a separate method, so you can use a return statement*.
void DoStuff()
{
try
{
if (!DoSomething())
return;
if (!DoSomething2())
return;
if (!DoSomething3())
return;
}
finally
{
DoSomethingElse();
}
}
To answer your question about when the finally code block is executed: it is always executed, unless the executing thread terminates prematurely.
*: Some restructuring is recommended, because there is no equivalent of the Delphi Exit. The break statement comes closest, but it can only be used in loop constructs or switch blocks. To mimic Exit behavior, you would need goto and a label. We wouldn't want that, now would we? :)
Why not make the three try-lines a common if/else block? Instead of exit, call the DoSomethingElse. Like so:
if (DoSomething() == false)
{
DoSomethingElse();
}
else if (DoSomething2() == false)
{
DoSomethingElse();
}
else if (DoSomething3() == false)
{
DoSomethingElse();
}
I would like to say that "C# is not Delphi", but that would be a bit arrogant.
In C#, finally is executed as well when return is called inside the try statement.
bool doSomething = false;
bool doSomething2 = true;
try
{
if( !doSomething )
{
Console.WriteLine ("not dosomething");
return;
}
if( !doSomething2 )
{
Console.WriteLine ("not dosomething 2");
return;
}
}
finally
{
Console.WriteLine ("In finally");
}
What about switch case of course If you don't mean the finally in c# by saying finally block. default case is the finally block then and you can also find flow control example and here at msdn : Flow Control (C# vs. Java)
static void Main(string[] args)
{
switch (args[0])
{
case "copy":
//...
break;
case "move":
//...
goto case "delete";
case "del":
case "remove":
case "delete":
//...
break;
default:
//...
break;
}
}
In this sort of situation, understanding the question as dealing exclusively with the non-exception handling case, I would refactor the contents of the try into a private helper method, like this
void BranchOnContext()
{
if (!DoSomething())
return;
if (!DoSomething2())
return;
// last one will drop out and return anyway
DoSomething3();
}
void DoStuff()
{
BranchOnContext(); // Assumed not to throw
DoSomethingElse(); // Always the next thing to be executed
}
EDIT -- tracking the changed requirement
void DoStuff()
{
string message = string.Empty;
try {
BranchOnContext();
} catch (MyExpectedException me) { // only catch exceptions I'm prepared to handle
message = me.Message;
}
DoSomethingElse(message); // Always the next thing to be executed
}
Taking another crack at this with the updated info:
I want DoSomethingElse to be executed
always and I want it to include
message from possible exception
If any of the DoSomething's return 0, null is returned. If not, the generic message is created. If there was an exception, it is caught and a message with its info is returned. How about this?
XElement OrderStatus(q_order_status Request)
{
try
{
if (DoSomething() != 0 )
{
return null;
}
else
{
return new XElement("SomeTag", "SomeResponse");
}
}
catch(Exception e)
{
// catch some errors and eventually pass the e.Message to the Response
return new XElement(e.tag, e.response);
}
}
Im still struggling with how to, in a good way, put finally into this.
I find it quite similar in behavior to the Delphi's one which I have shown on the beginning. I am interested in your comments. Response is dependent on the DoSomethings result.
XElement OrderStatus(q_order_status Request)
{
XElement Response;
int result = 0;
string Message = "";
try
{
result = DoSomething1();
if (result != 0)
{
throw new DoSomethingException("DoSomething1 has failed!");
}
result = DoSomething2();
if (result != 0)
{
throw new DoSomethingException("DoSomething2 has failed!");
}
result = DoSomething3();
if (result != 0)
{
throw new DoSomethingException("DoSomething3 has failed!");
}
Message = "All tests has been passed.";
}
catch(DoSomethingException e)
{
Message = e.Message;
}
catch(Exception e)
{
Message = e.Message;
}
finally
{
Response = new XElement("SomeTag", Message);
}
return Response;
}
What do you think?
void funcA()
{
if (!DoSomething())
return;
if (!DoSomething2())
return;
if (!DoSomething3())
return;
}
void funcB()
{
funcA();
DoSomethingElse;
}
This appears to replicate the delphi:-
try
{
if(DoSomething())
if(DoSomething2())
DoSomething3();
}
finally
{
DoSomethingElse();
}
an alternate style (some people will hate this style, others will love it.):-
try
{
DoSomething() && DoSomething2() && DoSomething3();
}
finally
{
DoSomethingElse();
}
I get the impression you want some other behaviour though?
Goto version?
try
{
if (!DoSomething())
goto Exit;
if (!DoSomething2())
goto Exit;
if (!DoSomething3())
goto Exit;
Exit:;
}
finally
{
DoSomethingElse();
}
Note the irritating ; after the label, it seems a label must precede a statement.
Just had an epiphany:-
Func<bool>[] somethings = new Func<bool>[] {DoSomething, DoSomething2, DoSomething3};
try
{
foreach (Func<bool> something in somethings)
{
if (!something())
break;
}
}
finally
{
DoSomethingElse();
}