如何通过模拟其方法正在使用的外部依赖来测试对象表达式方法?

How To Test Object expression methods by mocking external dependency which its mothod is using?

在编写单元测试时,@InjectMock 创建了 class 的实例并注入使用 @Mock.[= 定义的模拟实例14=]

所以当我们测试 class 的方法时,这工作正常。 我在测试对象表达式的方法时遇到问题。

例如: 我有一个对象 class DbService.

object DbService {
    private lateinit var connection: Connection
    init {
        makeConnection()
    }
    private fun makeConnection(){
        Class.forName("com.mysql.cj.jdbc.Driver")
        try{
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/Users", "user", "password")
        }catch (ex: Exception){
            println(ex)
        }
    }

    fun checkConnection(){
        var preparedStatement: PreparedStatement = connection.prepareStatement("SHOW DATABASES;")
        var resultSet = preparedStatement.executeQuery()
        while(resultSet.next()){
            println(resultSet.getObject(1))
        }
    }
}

现在我必须测试 checkConnection 功能。我该怎么做?

实际上做了更多的研究,我得到了一些提示并且对我有用。

就像,您可以使用 setter 方法进行手动依赖注入。

setter-based Dependency Injection

所以我做了什么,我又添加了一个函数来像这样手动设置连接对象。

object DbService {
    private lateinit var connection: Connection
    init {
        makeConnection()
    }
    private fun makeConnection(){
        Class.forName("com.mysql.cj.jdbc.Driver")
        try{
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/Users", "user", "password")
        }catch (ex: Exception){
            println(ex)
        }
    }
    
    // setter based dependency injection            <----
    fun initializeConnectionObject(conn: Connection){
        connection = conn
    }

    fun printingSomeMoreData(){
        var statement: Statement
        var resultSet: ResultSet
        var preparedStatement: PreparedStatement = connection.prepareStatement("SELECT * FROM titles where title=?;")
        preparedStatement.setString(1, "Engineer")
        resultSet = preparedStatement.executeQuery()
        val columnCount = resultSet.metaData.columnCount
        while(resultSet.next()){
            for(i in 1..columnCount){
                print(resultSet.getObject(i).toString() + " ")
            }
            println()
        }
    }

}

测试如下:

    @RunWith(MockitoJUnitRunner::class)
    class DbServiceTest {

    private lateinit var dbService: DbService
    @Mock lateinit var mockedConnection: Connection
    @Mock lateinit var mockedPreparedStatement: PreparedStatement
    @Mock lateinit var mockedResultSet: ResultSet
    @Mock
    lateinit var mockedResultSetMetaData: ResultSetMetaData

    @Before
    fun setUp(){
        MockitoAnnotations.initMocks(true)
    }

    @Test
    fun printingSomeMoreDataTest() {
        dbService = DbService
        Mockito.`when`(mockedResultSetMetaData.columnCount).thenReturn(3)
        Mockito.`when`(mockedResultSet.next()).thenReturn(true, true, true, true, false)
        Mockito.`when`(mockedResultSet.metaData).thenReturn(mockedResultSetMetaData)
        Mockito.`when`(mockedResultSet.getObject(1)).thenReturn("11", "21", "31", "41")
        Mockito.`when`(mockedResultSet.getObject(2)).thenReturn("12", "22", "32", "42")
        Mockito.`when`(mockedResultSet.getObject(3)).thenReturn("13", "23", "33", "43")
        Mockito.`when`(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet)
        Mockito.`when`(mockedConnection.prepareStatement(Mockito.anyString())).thenReturn(mockedPreparedStatement)
        dbService.initializeConnectionObject(mockedConnection)      // <----
        dbService.printingSomeMoreData()
        Mockito.verify(mockedResultSet, times(12)).getObject(anyInt())

    }
}