You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IntelliJ中Selenium登录E2E测试WebDriver空指针异常求助

问题描述

执行Selenium登录功能E2E测试时,持续抛出空指针异常:

java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.WebDriver.findElement(org.openqa.selenium.By)" because "SeleniumE2E.E2ETest.driver" is null

测试代码如下:

package SeleniumE2E;

import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class E2ETest {

  public static WebDriver driver;

  @BeforeMethod
   public void setUp() {
      try {
         System.setProperty("webdriver.gecko.driver", "C:\\Users\\picom\\Downloads\\geckodriver-v0.34.0-win64\\geckodriver.exe");

         FirefoxOptions options = new FirefoxOptions();
         options.addArguments("--headless");
         driver = new FirefoxDriver(options);
         driver.get("http://www.google.com");
         //driver.quit();
      } catch (Exception e) {
         e.printStackTrace();
         throw new RuntimeException("WebDriver initialization failed");
      }
   }

    @Test
    public void testLogin() {
        WebElement emailInput = driver.findElement(By.id("email"));
        emailInput.sendKeys("mariya@gmail.com");
        WebElement passwordInput = driver.findElement(By.id("password"));
        passwordInput.sendKeys("MAriya12!");

        WebElement loginButton = driver.findElement(By.xpath("//button[text()='Login']"));
        loginButton.click();

        String currentUrl = driver.getCurrentUrl();
        assertEquals("http://localhost:8080/Main.html", currentUrl);
    }

   @AfterMethod
   public void tearDown() {
      if (driver != null) {
         driver.quit();
      }
   }
}

附带的LoginRequestDto代码:

package com.example.demo.dto;

public class LoginRequestDto {

    private String email;
    private String password;

    public LoginRequestDto() {
    }

    // Getters and Setters
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

以及login.html代码:

<!DOCTYPE html>
<html>
<head>
    <title>User Login</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f4f4f4;
        }
        h2 {
            color: #333;
            text-align: center;
        }
        form {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            max-width: 400px;
            margin: 20px auto;
        }
        label {
            display: block;
            margin: 10px 0 5px;
        }
        input[type=text], input[type=password] {
            width: 100%;
            padding: 10px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }
        button {
            background-color: #008cba;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            margin-top: 20px;
        }
        button:hover {
            background-color: #005f73;
        }
    </style>
</head>
<body>
<h2>User Login</h2>
<form id="loginForm">
    <label for="email">Email:</label>
    <input type="text" id="email" name="email" required>

    <label for="password">Password:</label>
    <input type="password" id="password" name="password" required>

    <button type="button" onclick="login()">Login</button>
</form>
<p>Don't have an account? <a href="register">Register here</a>.</p>
<script>
    function login() {
        var email = document.getElementById("email").value;
        var password = document.getElementById("password").value;

        var loginData = {
            email: email,
            password: password
        };

        fetch('/api/user/login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(loginData)
        })
            .then(response => {
                if (response.redirected) {
                    window.location.href = response.url;
                } else {
                    console.error('Login failed');
                    alert('Invalid email or password');
                }
            })
            .catch(error => {
                console.error('Error:', error);
                alert('Error occurred while logging in');
            });
    }
</script>
</body>
</html>

已尝试切换Firefox驱动、修改driver访问修饰符为public static,均未解决问题,寻求其他修复方案。

解决方案

1. 统一测试框架注解

代码混合使用了JUnit 5(org.junit.jupiter.api.Test)和TestNG(@BeforeMethod、@AfterMethod)的注解,导致@BeforeMethod(TestNG)不会被JUnit 5执行,driver从未初始化。

修复方式二选一:

  • 改用TestNG:替换import org.junit.jupiter.api.Test;为import org.testng.annotations.Test;,确保测试运行器配置为TestNG;
  • 改用JUnit 5:替换@BeforeMethod、@AfterMethod为JUnit 5的@BeforeEach、@AfterEach,对应导入import org.junit.jupiter.api.BeforeEach;、import org.junit.jupiter.api.AfterEach;。

示例(JUnit 5版本):

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
// 其他导入保持不变

public class E2ETest {

  public WebDriver driver; // 移除static修饰符

  @BeforeEach
   public void setUp() {
      // 原有初始化逻辑不变
   }

    @Test
    public void testLogin() {
        // 原有测试逻辑不变
    }

   @AfterEach
   public void tearDown() {
      // 原有销毁逻辑不变
   }
}

2. 修正测试页面地址

setUp中当前打开的是http://www.google.com,但测试代码要查找登录页面的email、password元素,谷歌页面不存在这些元素。需要将driver.get("http://www.google.com")改为你的登录页面实际地址,例如http://localhost:8080/login.html。

3. 移除不必要的static修饰符

将public static WebDriver driver;改为public WebDriver driver;即可,static会导致多测试方法共享同一driver,容易引发并发问题,而JUnit 5/TestNG的前置方法会为每个测试方法独立初始化driver。

4. 检查GeckoDriver兼容性

确保GeckoDriver版本与Firefox浏览器版本匹配:

  • Firefox 115+ 对应GeckoDriver 0.33+;
  • 若Firefox是新版本,建议升级GeckoDriver至最新稳定版。

5. 增强初始化异常排查

在setUp的catch块中补充详细错误输出,确认是否是路径错误或浏览器启动失败导致driver未初始化:

catch (Exception e) {
    System.err.println("WebDriver初始化失败原因:" + e.getMessage());
    e.printStackTrace();
    throw new RuntimeException("WebDriver initialization failed", e);
}

内容的提问来源于stack exchange,提问作者Kate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:47:05