簡體   English   中英

如何在 Junit 測試用例中模擬 Spring JDBCTemplate 執行方法

[英]How to Mock Spring JDBCTemplate execute method in Junit Test case

當我執行第二個測試 testExecute_noException 時,仍然返回 null 指針異常。 對於第一個測試返回 null 指針異常是有效的,但對於第二個測試我需要繼續下一行測試。 請參閱下面的更多詳細信息。


實際代碼:

import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;

public class SimpleQueryExecutorTasklet implements Tasklet {

    private DataSource dataSource;
    private String sql;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        new JdbcTemplate(this.dataSource).execute(this.sql);
        return RepeatStatus.FINISHED;
    }
}

測試代碼:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.powermock.api.mockito.PowerMockito;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;

@RunWith(MockitoJUnitRunner.class)
public class SimpleQueryExecutorTaskletTest {

    @InjectMocks
    SimpleQueryExecutorTasklet simpleQueryExecutorTasklet;

    @Mock
    StepContribution stepContribution;

    @Mock
    ChunkContext chunkContext;

    @Mock
    JdbcTemplate jdbcTemplate;

    @Mock
    DataSource dataSource;

    String sql="select * from abc;";

    @Before
    public void setUp() throws Exception {
        simpleQueryExecutorTasklet.setDataSource(dataSource);
        simpleQueryExecutorTasklet.setSql(sql);
        PowerMockito.whenNew(JdbcTemplate.class).withAnyArguments().thenReturn(jdbcTemplate);
    }

    @Test(expected = NullPointerException.class)
    public void testExecute() throws Exception {
        simpleQueryExecutorTasklet.execute(stepContribution,chunkContext);
    }

    @Test
    public void testExecute_noException() throws Exception {
     Mockito.doNothing().when(jdbcTemplate).execute(Mockito.any(String.class));
        simpleQueryExecutorTasklet.execute(stepContribution,chunkContext);
        // Here will write some assertions
    }
}

Junit 執行的異常日志:

java.lang.NullPointerException
                at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:390)
                at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:428)
                at com.xxxxxx.api.accel.operations.SimpleQueryExecutorTasklet.execute(SimpleQueryExecutorTasklet.java:29)
                at com.xxxxxx.api.accel.operations.SimpleQueryExecutorTaskletTest.testExecute_noException(SimpleQueryExecutorTaskletTest.java:61)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:498)
                at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
                at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
                at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
                at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
                at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
                at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
                at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
                at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
                at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
                at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
                at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
                at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
                at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
                at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
                at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
                at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
                at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
                at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
                at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
                at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
                at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

您使用了錯誤的跑步者。 如果您使用的是 PowerMock,則需要PowerMockRunner 此外,當您進入 object 創建時,您需要使用@PrepareForTest

@RunWith(PowerMockRunner.class)
@PrepareForTest(JdbcTemplate.class)
public class SimpleQueryExecutorTaskletTest {
...
}

你可以試試下面的代碼

@RunWith(SpringJUnit4ClassRunner.class)
public class DaoImplTests{

    @Autowired
    private Dao dao;

    @Mock
    JdbcTemplate jdbcTemplate;

    @Test
    public void testUsingMockito() {
        try {
            User mockedUserInfo = new User();
            //setters
            mockedUserInfo.setXXX;
            mockedUserInfo.setYYY;

            Mockito.when(((JdbcDaoSupport)dao.getTemplate())).thenReturn(jdbcTemplate);
            Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), Mockito.any(Object[].class),
                    Mockito.any(RowMapper.class))).thenReturn(mockedUserInfo);
            User userInfo = dao.getUserInfo("");
            Assert.assertNotNull(userInfo);
            Assert.assertEquals(mockedUserInfo.getXXX(), userInfo.getXXX());
            //few more assertions
        } catch (Exception e) {
            Assert.fail(" : " + e.getMessage());
        }
    }

}

最后我發現問題出在主要的 class 方法上。 We are creating new JDBC template every time (not injecting) and thats the reason its failing though we are mocking the JDBC template in the junit method. 在更改主 class 代碼以注入 jdbc 模板后,它開始工作。

實際代碼:

import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

public class SimpleQueryExecutorTasklet implements Tasklet {

    private DataSource dataSource;
    private String sql;
    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    public void setSql(String sql) { this.sql = sql; }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }
    public JdbcTemplate getJdbcTemplate () {
        return this.jdbcTemplate == null ? new JdbcTemplate(dataSource) : this.jdbcTemplate;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        getJdbcTemplate().execute(this.sql);
        return RepeatStatus.FINISHED;
    }
}

測試代碼:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;

@RunWith(MockitoJUnitRunner.class)
public class SimpleQueryExecutorTaskletTest {

    @InjectMocks
    SimpleQueryExecutorTasklet simpleQueryExecutorTasklet;

    @Mock
    StepContribution stepContribution;

    @Mock
    ChunkContext chunkContext;

    @Mock
    JdbcTemplate jdbcTemplate;

    @Mock
    DataSource dataSource;

    String sql="select * from abc;";

    @Before
    public void setUp() throws Exception {
        simpleQueryExecutorTasklet.setDataSource(dataSource);
        simpleQueryExecutorTasklet.setSql(sql);
        //PowerMockito.whenNew(JdbcTemplate.class).withAnyArguments().thenReturn(jdbcTemplate);
    }

    @Test
    public void testExecute() throws Exception{
        simpleQueryExecutorTasklet.setJdbcTemplate(jdbcTemplate);
        RepeatStatus repeatStatus = simpleQueryExecutorTasklet.execute(stepContribution,chunkContext);
        assertNotNull(repeatStatus);
        assertSame("FINISHED", repeatStatus.toString());
    }
    @Test(expected = NullPointerException.class)
    public void testExecute_Exception() throws Exception{
        simpleQueryExecutorTasklet.setJdbcTemplate(null);
        simpleQueryExecutorTasklet.execute(stepContribution,chunkContext);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM