MSTest中ClassInitialize内调用方法触发空引用异常求助
问题:MSTest中使用[ClassInitialize]调用登录接口触发NullReferenceException
异常信息
Class Initialization method TestAutomation.Organisation2.OneTimeSetUp threw exception. System.NullReferenceException: Object reference not set to an instance of an object..
栈跟踪
Stack Trace: ILoginManager2.UILogin(IWebDriver driver, WebDriverWait wait) line 20 Organisation2.OneTimeSetUp(TestContext context) line 30 RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
相关代码
基类代码
namespace TestAutomation.TestBase { public class TestBaseClass { public static IWebDriver driver; public static WebDriverWait wait; [TestInitialize] public void DriverSetUp() { driver = new ChromeDriver(); driver.Manage().Window.Maximize(); wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5)); } } }
测试类代码
using TestAutomation.TestBase; namespace TestAutomation { [TestClass()] public class Organisation2: TestBaseClass { [ClassInitialize()] public static void OneTimeSetUp(TestContext context) { ILoginManager2.UILogin(driver, wait); // driver和wait继承自TestBaseClass } [TestInitialize] public void Login() { // code } [TestMethod()] public void CreateOrg() { // code } } }
登录接口代码
namespace SAMSAutomation { public interface ILoginManager2 { public static void UILogin(IWebDriver driver, WebDriverWait wait) { driver.Navigate().GoToUrl("https://www.example.com"); IWebElement tbUserName = driver.FindElement(By.Name("SWEUserName")); IWebElement tbPassword = driver.FindElement(By.Name("SWEPassword")); IWebElement bLogin = driver.FindElement(By.Id("s_swepi_22")); tbUserName.SendKeys("User"); tbPassword.SendKeys("Password"); bLogin.Click(); wait.Until(ExpectedConditions.ElementExists(By.LinkText("Home"))); } } }
原因分析
MSTest的执行顺序是**[ClassInitialize]先于[TestInitialize]执行**:
- 测试类的
OneTimeSetUp(标记[ClassInitialize])会在类中所有测试方法执行前运行 - 基类的
DriverSetUp(标记[TestInitialize])是在每个测试方法执行前才会运行 - 因此调用
ILoginManager2.UILogin时,driver和wait还未被初始化,传入的是null,触发空引用异常
解决方案
方案1:将driver初始化移到[ClassInitialize]中
修改测试类的OneTimeSetUp,先完成driver和wait的初始化,再调用登录:
[ClassInitialize()] public static void OneTimeSetUp(TestContext context) { // 先初始化driver和wait driver = new ChromeDriver(); driver.Manage().Window.Maximize(); wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5)); ILoginManager2.UILogin(driver, wait); }
同时调整基类,添加[ClassCleanup]确保测试后关闭浏览器,避免资源泄漏:
namespace TestAutomation.TestBase { public class TestBaseClass { public static IWebDriver driver; public static WebDriverWait wait; [ClassCleanup] public static void DriverTearDown() { // 安全关闭浏览器 driver?.Quit(); driver?.Dispose(); } } }
方案2:将初始化逻辑封装到基类的[ClassInitialize]
如果多个测试类都需要类似的初始化,可以把逻辑放到基类的静态方法中,子类自动继承执行:
namespace TestAutomation.TestBase { public class TestBaseClass { public static IWebDriver driver; public static WebDriverWait wait; [ClassInitialize] public static void BaseClassInitialize(TestContext context) { driver = new ChromeDriver(); driver.Manage().Window.Maximize(); wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5)); } [ClassCleanup] public static void DriverTearDown() { driver?.Quit(); driver?.Dispose(); } } }
测试类的OneTimeSetUp只需调用登录:
[ClassInitialize()] public static void OneTimeSetUp(TestContext context) { ILoginManager2.UILogin(driver, wait); }
注意事项
- 静态成员
driver和wait会在当前测试类的所有测试方法中共享,若测试项目启用并行测试,可能会导致不同测试类之间的资源冲突,这种情况下建议使用TestContext存储driver实例,或者为每个测试类创建独立的driver。 - 如果需要整个测试程序集只初始化一次浏览器,可以使用
[AssemblyInitialize]标记静态方法,但需注意后续测试方法可能受到之前测试状态的影响。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

