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

单元测试基于Firebase Auth的AuthenticationService类时遇方法问题求助

排查AuthenticationService登录方法单元测试问题的实操指南

首先,先把你没写完的代码补全(推测你是要抛出非法参数异常,或者通过listener回调错误),先假设完整的业务逻辑是这样的:

public void loginWithEmailAndPassword(String email, String password, OnCompletedListener listener) {
    // 邮箱合法性校验
    if (Strings.isNullOrEmpty(email) || !Pattern.compile(EMAIL_PATTERN).matcher(email).matches()) {
        throw new IllegalArgumentException("邮箱格式无效");
        // 如果是用listener回调错误,就是 listener.onFailure(new IllegalArgumentException(...));
    }
    
    // 后续Firebase Auth登录逻辑
    FirebaseAuth.getInstance()
        .signInWithEmailAndPassword(email, password)
        .addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                listener.onSuccess();
            } else {
                listener.onFailure(task.getException());
            }
        });
}

接下来分场景给你拆解测试方案,以及常见坑的排查方法:

1. 先搞定邮箱校验逻辑的测试(无需Mock Firebase)

这部分是纯业务逻辑,完全不需要碰Firebase,先把这部分测稳:

场景1:空邮箱/格式错误邮箱

如果你的代码是抛出异常,测试用例可以这么写:

@RunWith(MockitoJUnitRunner.class)
public class AuthenticationServiceTest {

    @InjectMocks
    private AuthenticationService authService;

    @Mock
    private OnCompletedListener mockListener;

    private static final String INVALID_EMAIL = "invalid-email";
    private static final String EMPTY_EMAIL = "";
    private static final String VALID_PASSWORD = "test123456";

    @Test(expected = IllegalArgumentException.class)
    public void loginWithEmptyEmail_ThrowsIllegalArgException() {
        authService.loginWithEmailAndPassword(EMPTY_EMAIL, VALID_PASSWORD, mockListener);
    }

    @Test(expected = IllegalArgumentException.class)
    public void loginWithInvalidEmailFormat_ThrowsIllegalArgException() {
        authService.loginWithEmailAndPassword(INVALID_EMAIL, VALID_PASSWORD, mockListener);
    }
}

如果你的代码是通过listener.onFailure()回调错误,那测试用例改成验证listener的调用:

@Test
public void loginWithInvalidEmail_CallsListenerOnFailure() {
    authService.loginWithEmailAndPassword(INVALID_EMAIL, VALID_PASSWORD, mockListener);
    
    // 验证回调了正确的异常
    verify(mockListener).onFailure(any(IllegalArgumentException.class));
}

2. Mock Firebase Auth,测试登录逻辑

因为FirebaseAuth是通过静态方法getInstance()获取实例的,所以需要用PowerMock来Mock静态方法,步骤如下:

第一步:配置PowerMock测试环境

在测试类上添加必要的注解:

@RunWith(PowerMockRunner.class)
// 告诉PowerMock要准备Mock的静态类
@PrepareForTest(FirebaseAuth.class)
public class AuthenticationServiceTest {

    // Mock FirebaseAuth实例
    @Mock
    private FirebaseAuth mockFirebaseAuth;
    // Mock登录返回的Task和AuthResult
    @Mock
    private Task<AuthResult> mockLoginTask;
    @Mock
    private AuthResult mockAuthResult;
    // 注入被测试的AuthenticationService
    @InjectMocks
    private AuthenticationService authService;
    // Mock回调监听器
    @Mock
    private OnCompletedListener mockListener;

    private static final String VALID_EMAIL = "test@example.com";
    private static final String VALID_PASSWORD = "test123456";

    @Before
    public void setUp() {
        // 初始化静态Mock:当调用FirebaseAuth.getInstance()时返回我们的mock实例
        PowerMockito.mockStatic(FirebaseAuth.class);
        when(FirebaseAuth.getInstance()).thenReturn(mockFirebaseAuth);
    }
}

场景2:合法凭证,登录成功

@Test
public void loginWithValidCredentials_TriggersOnSuccess() throws Exception {
    // 模拟Firebase调用返回成功的Task
    when(mockFirebaseAuth.signInWithEmailAndPassword(VALID_EMAIL, VALID_PASSWORD))
        .thenReturn(mockLoginTask);
    when(mockLoginTask.isSuccessful()).thenReturn(true);

    // 执行测试方法
    authService.loginWithEmailAndPassword(VALID_EMAIL, VALID_PASSWORD, mockListener);

    // 验证监听器的onSuccess被调用
    verify(mockListener).onSuccess();
}

场景3:非法密码,登录失败

@Test
public void loginWithInvalidPassword_TriggersOnFailure() throws Exception {
    // 模拟登录失败的异常
    FirebaseAuthInvalidCredentialsException mockException = 
        new FirebaseAuthInvalidCredentialsException("INVALID_PASSWORD", "密码错误");
    
    // 模拟Firebase调用返回失败的Task
    when(mockFirebaseAuth.signInWithEmailAndPassword(VALID_EMAIL, VALID_PASSWORD))
        .thenReturn(mockLoginTask);
    when(mockLoginTask.isSuccessful()).thenReturn(false);
    when(mockLoginTask.getException()).thenReturn(mockException);

    // 执行测试方法
    authService.loginWithEmailAndPassword(VALID_EMAIL, VALID_PASSWORD, mockListener);

    // 验证监听器的onFailure被调用,且传入了正确的异常
    verify(mockListener).onFailure(mockException);
}

常见问题排查清单

  • 静态Mock失效:一定要加@PrepareForTest(FirebaseAuth.class),并且用PowerMockRunner运行测试。如果用JUnit 5,需要换成PowerMock的JUnit 5扩展(PowerMockExtension)。
  • 依赖注入失败:检查@InjectMocks是否正确识别了AuthenticationService的依赖,确保所有需要Mock的对象都用@Mock注解初始化了。
  • 测试逻辑和业务逻辑不匹配:如果你的业务逻辑是用listener回调错误,就不要写expected = Exception.class的测试,反之亦然。
  • Pattern编译的小坑:如果EMAIL_PATTERN是在方法内部每次调用都编译,建议把它改成静态常量(private static final Pattern EMAIL_PATTERN = Pattern.compile(...)),避免重复编译影响测试性能和稳定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:31:12