我有一个Selenium测试.DLL被加载使用NUnit.
我运行所需的硒Java服务器悄悄藏在一个进程中运行测试时.
不过,我目前启动服务器当测试开始和Kill()
它的当测试停止.
这导致每个测试启动/停止 selenium服务器.
我想要的是Selenium Server进程:
开始在任DLL加载/初始化或第一次测试开始时
被Kill()
编上DLL死亡或垃圾收集
我读到C#不支持捕获DLL初始化和调用代码.(我错了吗?)
我的想法是将Selenium服务器托管在单例类中,并在第一次测试运行时对其进行初始化.然后我将它留给垃圾收集器通过解构器调用Dispose方法.我目前有以下代码来托管selenium服务器:
namespace Tests.Server { using System; using System.Diagnostics; using System.IO; using System.Security; using System.Windows.Forms; using Microsoft.Win32; ////// A singleton class to host and control the selenium server. /// public class SeleniumServer : IDisposable { #region Fields ////// The singleton instance /// private static volatile SeleniumServer instance; ////// An object to perform double-check locking upon instance creation to /// avoid dead-locks. /// See private static object syncRoot = new Object(); ///for more information. /// /// The current selenium server. /// private Process seleniumServer = null; ////// A flag for the disposal of the class. /// private bool isDisposed = false; #endregion #region Constructor ////// Initializes a new instance of the SeleniumServer class. Starts the /// Selenium Java server in a background hidden thread. /// private SeleniumServer() { // Get the java install folder. string javaFileLocation = this.GetJavaFileLocation(); // Get the selenium server java executable string jarFileLocation = '"' + Directory.GetCurrentDirectory() + @"\SeleniumServer\selenium-server.jar"""; // Start the selenium server seleniumServer = new Process(); seleniumServer.StartInfo.FileName = javaFileLocation; seleniumServer.StartInfo.Arguments = " -jar " + jarFileLocation + " -browserSessionReuse -trustAllSSLCertification"; seleniumServer.StartInfo.WorkingDirectory = jarFileLocation.Substring(0, jarFileLocation.LastIndexOf("\\")); seleniumServer.StartInfo.UseShellExecute = true; seleniumServer.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; seleniumServer.Start(); } #endregion #region Deconstructor ~SeleniumServer() { Dispose(false); } #endregion #region Properties ////// A thread safe /// public static SeleniumServer Instance { get { // This approach ensures that only one instance is created and // only when the instance is needed. Also, the variable is // declared to be volatile to ensure that assignment to the // instance variable completes before the instance variable can // be accessed. Lastly, this approach uses a syncRoot instance // to lock on, rather than locking on the type itself, to avoid // deadlocks. // This double-check locking approach solves the thread // concurrency problems while avoiding an exclusive lock in // every call to the Instance property method. It also allows // you to delay instantiation until the object is first // accessed. In practice, an application rarely requires this // type of implementation. In most cases, the static // initialization approach is sufficient. if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new SeleniumServer(); } } } return instance; } } #endregion #region Methods ////// Stops the process. /// protected void Dispose(bool disposing) { if (disposing) { // Code to dispose the managed resources of the class // Not needed right now. } // Code to dispose the un-managed resources of the class // TODO: Handle the exceptions Instance.seleniumServer.Kill(); // All done! isDisposed = true; } ////// Dispose of the class and stop the Selenium server process. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ////// Stops the Selenium Server. /// public void Stop() { this.Dispose(); } ////// Attempts to get the Java installation folder from the registry. If /// it cannot be found the default installation folder is checked before /// failing. /// ///The Java executable file path. ////// Thrown when the user does not have permission to access the /// registry. /// ////// Thrown if the registry key object is disposed of. /// ////// Thrown if the registry key object is marked for deletion. /// private string GetJavaFileLocation() { string javaFileLocation = string.Empty; RegistryKey regKey = Registry.LocalMachine; RegistryKey subKey = null; try { // Check for Java in the native bitness string javaRegistryLocation = @"SOFTWARE\JavaSoft\Java Runtime Environment\"; subKey = regKey.OpenSubKey(javaRegistryLocation); // Check if we are running in WOW64 and only 32 bit Java is installed. if (subKey == null) { javaRegistryLocation = @"SOFTWARE\Wow6432Node\JavaSoft\Java Runtime Environment\"; subKey = regKey.OpenSubKey(javaRegistryLocation); } // If Java was not found in either of these location the user // needs to install it. Note that Java 32 bit is a prerequisite // for the installer so should always be installed. if (subKey == null) { MessageBox.Show( "You must have Java installed to run the commands server. This allows browser commands to be routed to the browser window.\n\nPlease visit: http://www.java.com/ to download.", "Please Install Java", MessageBoxButtons.OK, MessageBoxIcon.Information); throw new Exception("No installation of Java was detected to run the selenium server."); } // Get all the sub keys (could be multiple versions of Java // installed) and get the most recent (last one) string[] subKeyNames = subKey.GetSubKeyNames(); subKey = regKey.OpenSubKey(javaRegistryLocation + subKeyNames[subKeyNames.Length - 1]); // Specify the java executable location javaFileLocation = subKey.GetValue("JavaHome").ToString() + @"\bin\java.exe"; } catch (SecurityException e) { // Attempt to find the java executable at the default location. javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe"; if (!File.Exists(javaFileLocation)) { MessageBox.Show( "The program did not have permission to access the registry to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.", "Java Executable Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception("The program did not have permission to access the registry to obtain the installation folder of Java.", e); } } catch (UnauthorizedAccessException e) { // Attempt to find the java executable at the default location. javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe"; if (!File.Exists(javaFileLocation)) { MessageBox.Show( "The user does not have the necessary registry rights to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.", "Java Executable Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception("The user does not have the necessary registry rights to obtain the installation folder of Java.", e); } } catch (ObjectDisposedException e) { // This hopefully shouldn't happen so ask the user to report it. MessageBox.Show( "The Java registry object was closed, resulting in the Java server not being started. Please report this error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new ObjectDisposedException("The Java registry object was closed. Please report this error.", e); } catch (IOException e) { // This hopefully shouldn't happen so ask the user to report it. MessageBox.Show( "The Java registry object was marked for deletion, resulting in the Java server not being started. Please report this error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new ObjectDisposedException("The Java registry object was marked for deletion. Please report this error.", e); } return javaFileLocation; } #endregion } }
我的问题是:
这是一个主持DLL生命周期的合理方法吗?
如何从我的代码中设置此类?它需要静态/全局吗?使用你知道的单身人士的任何好例子?
垃圾收集会在DLL卸载时处理这个单例吗?
我可以将进程作为我的DLL的子进程托管,即使DLL不会持续活动,因为NUnit只会在离散时间点执行DLL中的测试吗?
Matt Clarkso.. 6
管理它:
//// Copyright (c) 2010 All Right Reserved // //// Provides a singleton class for hosting and running the selenium server. // namespace YourCompany.Tests.Server { using System; using System.Diagnostics; using System.IO; using System.Security; using System.Windows.Forms; using Microsoft.Win32; ////// A singleton class to host and control the selenium server. /// public sealed class SeleniumServer : IDisposable { #region Fields ////// The singleton instance /// private static volatile SeleniumServer instance; ////// An object to perform double-check locking upon instance creation to /// avoid dead-locks. /// See private static object syncRoot = new object(); ///for more information. /// /// The current selenium server. /// private Process seleniumServer = null; ////// A flag for the disposal of the class. /// private bool isDisposed = false; #endregion #region Constructor ////// Prevents a default instance of the SeleniumServer class from being created. Starts the Selenium Java server in a background hidden thread. /// private SeleniumServer() { // Get the java install folder. string javaFileLocation = this.GetJavaFileLocation(); // Get the selenium server java executable string jarFileLocation = '"' + Directory.GetCurrentDirectory() + @"\SeleniumServer\selenium-server.jar"""; // Start the selenium server this.seleniumServer = new Process(); this.seleniumServer.StartInfo.FileName = javaFileLocation; this.seleniumServer.StartInfo.Arguments = " -jar " + jarFileLocation + " -browserSessionReuse -trustAllSSLCertificates"; this.seleniumServer.StartInfo.WorkingDirectory = jarFileLocation.Substring(0, jarFileLocation.LastIndexOf("\\")); this.seleniumServer.StartInfo.UseShellExecute = true; this.seleniumServer.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; this.seleniumServer.Start(); // The class is no long disposed this.isDisposed = false; } #endregion #region Deconstructor ////// Finalizes an instance of the SeleniumServer class. /// ~SeleniumServer() { this.Dispose(false); } #endregion #region Properties ////// Gets a thread safe instance of the Selenium Server class. /// public static SeleniumServer Instance { get { // This approach ensures that only one instance is created and // only when the instance is needed. Also, the variable is // declared to be volatile to ensure that assignment to the // instance variable completes before the instance variable can // be accessed. Lastly, this approach uses a syncRoot instance // to lock on, rather than locking on the type itself, to avoid // deadlocks. // This double-check locking approach solves the thread // concurrency problems while avoiding an exclusive lock in // every call to the Instance property method. It also allows // you to delay instantiation until the object is first // accessed. In practice, an application rarely requires this // type of implementation. In most cases, the static // initialization approach is sufficient. if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new SeleniumServer(); } } } return instance; } } #endregion #region Methods ////// Dispose of the class and stop the Selenium server process. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } ////// Stops the process. /// /// /// True if managed resources need to be disposed /// private void Dispose(bool disposing) { if (!this.isDisposed) { if (disposing) { // If this class is expanded: // Code to dispose the managed resources of the class } // Kill the server if (this.seleniumServer != null) { try { this.seleniumServer.Kill(); this.seleniumServer = null; } catch (Exception) { MessageBox.Show( "The Selenium Java Server could not be stopped, please start Task Manager and killed \"java.exe\"", "Failed to Stop Jave Server", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } // All done! this.isDisposed = true; } ////// Attempts to get the Java installation folder from the registry. If /// it cannot be found the default installation folder is checked before /// failing. /// ///The Java executable file path. ////// Thrown when the user does not have permission to access the /// registry. /// ////// Thrown if the registry key object is disposed of. /// ////// Thrown if the registry key object is marked for deletion. /// private string GetJavaFileLocation() { string javaFileLocation = string.Empty; RegistryKey regKey = Registry.LocalMachine; RegistryKey subKey = null; try { // Check for Java in the native bitness string javaRegistryLocation = @"SOFTWARE\JavaSoft\Java Runtime Environment\"; subKey = regKey.OpenSubKey(javaRegistryLocation); // Check if we are running in WOW64 and only 32 bit Java is installed. if (subKey == null) { javaRegistryLocation = @"SOFTWARE\Wow6432Node\JavaSoft\Java Runtime Environment\"; subKey = regKey.OpenSubKey(javaRegistryLocation); } // If Java was not found in either of these location the user // needs to install it. Note that Java 32 bit is a prerequisite // for the installer so should always be installed. if (subKey == null) { MessageBox.Show( "You must have Java installed to run the commands server. This allows browser commands to be routed to the browser window.\n\nPlease visit: http://www.java.com/ to download.", "Please Install Java", MessageBoxButtons.OK, MessageBoxIcon.Information); throw new Exception("No installation of Java was detected to run the selenium server."); } // Get all the sub keys (could be multiple versions of Java // installed) and get the most recent (last one) string[] subKeyNames = subKey.GetSubKeyNames(); subKey = regKey.OpenSubKey(javaRegistryLocation + subKeyNames[subKeyNames.Length - 1]); // Specify the java executable location javaFileLocation = subKey.GetValue("JavaHome").ToString() + @"\bin\java.exe"; } catch (SecurityException e) { // Attempt to find the java executable at the default location. javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe"; if (!File.Exists(javaFileLocation)) { MessageBox.Show( "The program did not have permission to access the registry to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.", "Java Executable Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception("The program did not have permission to access the registry to obtain the installation folder of Java.", e); } } catch (UnauthorizedAccessException e) { // Attempt to find the java executable at the default location. javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe"; if (!File.Exists(javaFileLocation)) { MessageBox.Show( "The user does not have the necessary registry rights to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.", "Java Executable Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception("The user does not have the necessary registry rights to obtain the installation folder of Java.", e); } } catch (ObjectDisposedException e) { // This hopefully shouldn't happen so ask the user to report it. MessageBox.Show( "The Java registry object was closed, resulting in the Java server not being started. Please report this error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new ObjectDisposedException("The Java registry object was closed. Please report this error.", e); } catch (IOException e) { // This hopefully shouldn't happen so ask the user to report it. MessageBox.Show( "The Java registry object was marked for deletion, resulting in the Java server not being started. Please report this error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new ObjectDisposedException("The Java registry object was marked for deletion. Please report this error.", e); } return javaFileLocation; } #endregion } }
刚做:
SeleniumServer seleniumServer = SeleniumServer.Instance;
在SetUp开始时启动服务器.
以为我会发帖以防万一有人搜索这个问题.
管理它:
//// Copyright (c) 2010 All Right Reserved // //// Provides a singleton class for hosting and running the selenium server. // namespace YourCompany.Tests.Server { using System; using System.Diagnostics; using System.IO; using System.Security; using System.Windows.Forms; using Microsoft.Win32; ////// A singleton class to host and control the selenium server. /// public sealed class SeleniumServer : IDisposable { #region Fields ////// The singleton instance /// private static volatile SeleniumServer instance; ////// An object to perform double-check locking upon instance creation to /// avoid dead-locks. /// See private static object syncRoot = new object(); ///for more information. /// /// The current selenium server. /// private Process seleniumServer = null; ////// A flag for the disposal of the class. /// private bool isDisposed = false; #endregion #region Constructor ////// Prevents a default instance of the SeleniumServer class from being created. Starts the Selenium Java server in a background hidden thread. /// private SeleniumServer() { // Get the java install folder. string javaFileLocation = this.GetJavaFileLocation(); // Get the selenium server java executable string jarFileLocation = '"' + Directory.GetCurrentDirectory() + @"\SeleniumServer\selenium-server.jar"""; // Start the selenium server this.seleniumServer = new Process(); this.seleniumServer.StartInfo.FileName = javaFileLocation; this.seleniumServer.StartInfo.Arguments = " -jar " + jarFileLocation + " -browserSessionReuse -trustAllSSLCertificates"; this.seleniumServer.StartInfo.WorkingDirectory = jarFileLocation.Substring(0, jarFileLocation.LastIndexOf("\\")); this.seleniumServer.StartInfo.UseShellExecute = true; this.seleniumServer.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; this.seleniumServer.Start(); // The class is no long disposed this.isDisposed = false; } #endregion #region Deconstructor ////// Finalizes an instance of the SeleniumServer class. /// ~SeleniumServer() { this.Dispose(false); } #endregion #region Properties ////// Gets a thread safe instance of the Selenium Server class. /// public static SeleniumServer Instance { get { // This approach ensures that only one instance is created and // only when the instance is needed. Also, the variable is // declared to be volatile to ensure that assignment to the // instance variable completes before the instance variable can // be accessed. Lastly, this approach uses a syncRoot instance // to lock on, rather than locking on the type itself, to avoid // deadlocks. // This double-check locking approach solves the thread // concurrency problems while avoiding an exclusive lock in // every call to the Instance property method. It also allows // you to delay instantiation until the object is first // accessed. In practice, an application rarely requires this // type of implementation. In most cases, the static // initialization approach is sufficient. if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new SeleniumServer(); } } } return instance; } } #endregion #region Methods ////// Dispose of the class and stop the Selenium server process. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } ////// Stops the process. /// /// /// True if managed resources need to be disposed /// private void Dispose(bool disposing) { if (!this.isDisposed) { if (disposing) { // If this class is expanded: // Code to dispose the managed resources of the class } // Kill the server if (this.seleniumServer != null) { try { this.seleniumServer.Kill(); this.seleniumServer = null; } catch (Exception) { MessageBox.Show( "The Selenium Java Server could not be stopped, please start Task Manager and killed \"java.exe\"", "Failed to Stop Jave Server", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } // All done! this.isDisposed = true; } ////// Attempts to get the Java installation folder from the registry. If /// it cannot be found the default installation folder is checked before /// failing. /// ///The Java executable file path. ////// Thrown when the user does not have permission to access the /// registry. /// ////// Thrown if the registry key object is disposed of. /// ////// Thrown if the registry key object is marked for deletion. /// private string GetJavaFileLocation() { string javaFileLocation = string.Empty; RegistryKey regKey = Registry.LocalMachine; RegistryKey subKey = null; try { // Check for Java in the native bitness string javaRegistryLocation = @"SOFTWARE\JavaSoft\Java Runtime Environment\"; subKey = regKey.OpenSubKey(javaRegistryLocation); // Check if we are running in WOW64 and only 32 bit Java is installed. if (subKey == null) { javaRegistryLocation = @"SOFTWARE\Wow6432Node\JavaSoft\Java Runtime Environment\"; subKey = regKey.OpenSubKey(javaRegistryLocation); } // If Java was not found in either of these location the user // needs to install it. Note that Java 32 bit is a prerequisite // for the installer so should always be installed. if (subKey == null) { MessageBox.Show( "You must have Java installed to run the commands server. This allows browser commands to be routed to the browser window.\n\nPlease visit: http://www.java.com/ to download.", "Please Install Java", MessageBoxButtons.OK, MessageBoxIcon.Information); throw new Exception("No installation of Java was detected to run the selenium server."); } // Get all the sub keys (could be multiple versions of Java // installed) and get the most recent (last one) string[] subKeyNames = subKey.GetSubKeyNames(); subKey = regKey.OpenSubKey(javaRegistryLocation + subKeyNames[subKeyNames.Length - 1]); // Specify the java executable location javaFileLocation = subKey.GetValue("JavaHome").ToString() + @"\bin\java.exe"; } catch (SecurityException e) { // Attempt to find the java executable at the default location. javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe"; if (!File.Exists(javaFileLocation)) { MessageBox.Show( "The program did not have permission to access the registry to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.", "Java Executable Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception("The program did not have permission to access the registry to obtain the installation folder of Java.", e); } } catch (UnauthorizedAccessException e) { // Attempt to find the java executable at the default location. javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe"; if (!File.Exists(javaFileLocation)) { MessageBox.Show( "The user does not have the necessary registry rights to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.", "Java Executable Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception("The user does not have the necessary registry rights to obtain the installation folder of Java.", e); } } catch (ObjectDisposedException e) { // This hopefully shouldn't happen so ask the user to report it. MessageBox.Show( "The Java registry object was closed, resulting in the Java server not being started. Please report this error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new ObjectDisposedException("The Java registry object was closed. Please report this error.", e); } catch (IOException e) { // This hopefully shouldn't happen so ask the user to report it. MessageBox.Show( "The Java registry object was marked for deletion, resulting in the Java server not being started. Please report this error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new ObjectDisposedException("The Java registry object was marked for deletion. Please report this error.", e); } return javaFileLocation; } #endregion } }
刚做:
SeleniumServer seleniumServer = SeleniumServer.Instance;
在SetUp开始时启动服务器.
以为我会发帖以防万一有人搜索这个问题.