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

Spring MVC+JUnit测试:Repository调用时出现NullPointerException

解决JUnit测试Spring MVC Repository时的NullPointerException问题

咱们先捋清楚你遇到的问题:给Spring MVC项目里的Repository写JUnit测试时,调用findByLoginInformations方法触发了NullPointerException,错误指向实现类的第77行,也就是操作sessionFactory的代码块。先把你的相关代码整理清楚:

相关代码

PersonneRepository接口

public interface PersonneRepository { 
    void setSessionFactory(SessionFactory sessionFactory); 
    Personne findByLoginInformations(String email, String password); 
}

PersonneRepositoryImpl实现类

@Repository 
public class PersonneRepositoryImpl implements PersonneRepository { 
    private SessionFactory sessionFactory; 

    @Autowired 
    public void setSessionFactory(SessionFactory sessionFactory) { 
        this.sessionFactory = sessionFactory; 
    } 

    public Personne findByLoginInformations(String email, String password){ 
        Session session; 
        try { 
            session = sessionFactory.getCurrentSession(); 
        } catch (HibernateException e) { 
            session = sessionFactory.openSession(); 
        } 
        Query query = session 
                .createQuery("FROM Personne p WHERE p.email = :email AND p.password = :password") 
                .setParameter("email", email) 
                .setParameter("password", password); 
        return (Personne)query.uniqueResult(); 
    } 
}

原测试类

public class PersonneRepositoryTest { 
    @Mock 
    private SessionFactory sessionFactory; 
    @InjectMocks 
    private PersonneRepositoryImpl personneRepositoryImpl; 

    @Before 
    public void setUp() { 
        MockitoAnnotations.initMocks(this); 
    } 

    @Test 
    public void testFindPersonne(){ 
        Personne p = new Personne(); 
        p.setId(1); 
        when(personneRepositoryImpl.findByLoginInformations("ayoub", "aaaa")).thenReturn(p); 
        assertEquals(p, personneRepositoryImpl.findById(1)); 
        verify(personneRepositoryImpl).findById(1); 
    } 
}

问题排查

咱们拆解下核心问题:

  1. 测试逻辑完全走偏了:你现在是在mockpersonneRepositoryImpl自己的findByLoginInformations方法,然后去调用一个根本不存在的findById方法(你的Repository接口里没有这个方法,明显是笔误),这完全没测试到你写的实现类真实逻辑。
  2. NPE的直接原因:虽然你用@Mock创建了sessionFactory的代理对象,但Mockito默认会给所有未指定返回值的方法返回null。当你调用findByLoginInformations时,实际执行的是实现类的代码,sessionFactory.getCurrentSession()返回null,catch块里的sessionFactory.openSession()也返回null,导致session变量为null,后续调用session.createQuery()就触发了NPE。

修复方案

咱们需要修正测试逻辑,正确mock依赖对象的行为,来测试实现类的真实逻辑:

修正后的测试类

public class PersonneRepositoryTest {
    // Mock所有需要的依赖对象
    @Mock
    private SessionFactory sessionFactory;
    @Mock
    private Session session;
    @Mock
    private Query query;

    // 注入要测试的实现类
    @InjectMocks
    private PersonneRepositoryImpl personneRepositoryImpl;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testFindByLoginInformations() {
        // 1. 准备预期的返回对象
        Personne expectedPersonne = new Personne();
        expectedPersonne.setId(1);
        expectedPersonne.setEmail("ayoub");
        expectedPersonne.setPassword("aaaa");

        // 2. 模拟依赖对象的行为
        // 让sessionFactory.getCurrentSession()返回mock的session
        when(sessionFactory.getCurrentSession()).thenReturn(session);
        // 让session创建query时返回mock的query
        when(session.createQuery("FROM Personne p WHERE p.email = :email AND p.password = :password"))
                .thenReturn(query);
        // 模拟链式调用的setParameter方法,返回query自身
        when(query.setParameter("email", "ayoub")).thenReturn(query);
        when(query.setParameter("password", "aaaa")).thenReturn(query);
        // 让query返回预期的Personne对象
        when(query.uniqueResult()).thenReturn(expectedPersonne);

        // 3. 调用要测试的方法
        Personne actualPersonne = personneRepositoryImpl.findByLoginInformations("ayoub", "aaaa");

        // 4. 断言结果是否符合预期
        assertEquals(expectedPersonne, actualPersonne);

        // 5. 验证依赖方法是否被正确调用
        verify(sessionFactory).getCurrentSession();
        verify(session).createQuery(anyString());
        verify(query, times(2)).setParameter(anyString(), anyString());
        verify(query).uniqueResult();
    }
}

额外注意事项

  • 删掉测试里的findById相关代码,那是笔误,咱们的测试目标是findByLoginInformations方法。
  • 不要mock你要测试的类本身(也就是personneRepositoryImpl),而是mock它的依赖(sessionFactory、Session、Query),这样才能测试你自己写的业务逻辑。
  • 如果要测试catch块的逻辑(比如getCurrentSession抛出异常的情况),可以用when(sessionFactory.getCurrentSession()).thenThrow(new HibernateException("test exception"))来模拟异常场景,验证是否会调用openSession。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:41:09