kotlinjunitmockitodaoebean

NullPointerException: Testing DAO class that uses Ebean with Mockito and JUnit, Kotlin


So I have a quite basic model, dao, and controller classes written in kotlin. I am using Ebean to connect the service and data. I am trying to create unit tests for my DAO classes. To my understanding unit tests should not actually invoke the db connection even tho I have read that some have combined my stack with DBUnit to make such tests.

However I chose different approach with Mockito and tried to follow ebean instructions on how to do it as described in here: https://ebean.io/docs/setup/testing I was able to create the mock database object and run the test with the getBeanId(null) function. But when I try to change the

when(dbmock.getBeanId(null)).thenReturn(someBeanId)

to

when(dbmock.find(PracticeSession::class.java).where(Expr.eq("id", 1)).findOne()!!).thenReturn(mockPracticeSession)

I get this error: java.lang.NullPointerException: Cannot invoke "io.ebean.Query.where(io.ebean.Expression)" because the return value of "io.ebean.Database.find(java.lang.Class)" is null

So any advice how I should continue with this or what I am doing wrong? To me it looks like the dbmock is not the same as the real DB object since only some functions are working i. e. getBeanId works but find() doesn't. Do I need to initialize it with something? I am assuming there will be a problem also when the DB.find() is called in the DAO class.

Here are my model,


import io.ebean.Model
import io.ebean.annotation.NotNull
import org.flywaydb.core.internal.configuration.ConfigUtils.TABLE
import java.util.*
import javax.persistence.*

@Entity
class PracticeSession : Model() {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = 0

    var name: String? = null

    @NotNull
    var date: Date? = null

    @NotNull
    var duration = 0

    @ManyToOne(optional = false)
    var location: Location? = null

    @ManyToOne(optional = false)
    var climber: Climber? = null
}

dao,


import io.ebean.DB
import io.ebean.Expr
import model.PracticeSession
import utils.ApplicationException

class PracticeSessionDAO {
    @Throws(ApplicationException::class)
    fun getPracticeSession(practice_session_id: Int): PracticeSession {
        try {
            return DB.find(PracticeSession::class.java).where(Expr.eq("id", practice_session_id)).findOne()!!
        } catch (e:Exception){
            throw ApplicationException("PracticeSession with id: $practice_session_id was not found. Returned error: $e")
        }

    }

}

and test classes

package dao.sqlserver

import io.ebean.DB
import io.ebean.Database
import io.ebean.Expr
import io.ebean.MockiEbean
import model.PracticeSession
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test

import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import io.ebeaninternal.server.core.DefaultServer
import org.mockito.InjectMocks

internal class PracticeSessionDAOTestMock {

    lateinit var defaultServer : Database
    lateinit var restoredServer : Database


    @BeforeEach
    fun setUp() {

        defaultServer = DB.getDefault()
        assertTrue(defaultServer is DefaultServer)

    }

    @AfterEach
    fun tearDown() {
        restoredServer = DB.getDefault()
        assertTrue(restoredServer is DefaultServer)
    }

    @Test
    fun getPracticeSession() {
        val dbmock = Mockito.mock(Database::class.java)
        val mockPracticeSession = PracticeSession()
        mockPracticeSession.id=1
        `when`(dbmock.find(PracticeSession::class.java).where(Expr.eq("id", 1)).findOne()!!).thenReturn(mockPracticeSession)
        //val someBeanId = java.lang.Long.valueOf(47L)
        //`when`(dbmock.getBeanId(null)).thenReturn(someBeanId)
        val mockiEbean = MockiEbean.start(dbmock)
        try{
            val mockServer = DB.getDefault()
            //val beanId: Any = mockServer.getBeanId(null)
            //assertEquals(someBeanId, beanId);
            val practiceSessionDAO = PracticeSessionDAO()
            val practiceSession = practiceSessionDAO.getPracticeSession(1)
            assertEquals(1, practiceSession.id)
        } finally {
            mockiEbean.restoreOriginal()
        }

    }
}

Solution

  • Okey so I was able to solve this issue. This pointed me to correct direction: Mockito - NullpointerException when stubbing Method

    Here is the corrected Test class. I just had to mock and stubb bunch of classes and functions.

    package dao.sqlserver
    
    import io.ebean.*
    import model.PracticeSession
    import org.junit.jupiter.api.AfterEach
    import org.junit.jupiter.api.Test
    import org.junit.jupiter.api.Assertions.*
    import org.junit.jupiter.api.BeforeEach
    import org.mockito.Mockito
    import org.mockito.Mockito.`when`
    import io.ebeaninternal.server.core.DefaultServer
    
    
    internal class PracticeSessionDAOTestMock {
    
        lateinit var defaultServer : Database
        lateinit var restoredServer : Database
    
    
    
       @BeforeEach
        fun setUp() {
    
            defaultServer = DB.getDefault()
            assertTrue(defaultServer is DefaultServer)
    
        }
    
        @AfterEach
        fun tearDown() {
            restoredServer = DB.getDefault()
            assertTrue(restoredServer is DefaultServer)
        }
    
        @Test
        fun getPracticeSession() {
            val dbmock = Mockito.mock(Database::class.java)
            val mockPracticeSession = PracticeSession()
            mockPracticeSession.id=1
            val mockQuery = Mockito.mock(Query::class.java)
            val mockExprFactory = Mockito.mock(ExpressionFactory::class.java)
            `when`(dbmock.find(PracticeSession::class.java)).thenReturn(mockQuery as Query<PracticeSession>?)
            `when`(dbmock.getExpressionFactory()).thenReturn(mockExprFactory)
            `when`(mockQuery.where(mockExprFactory.eq("id",1))).thenReturn(mockQuery)
            `when`(mockQuery.findOne()).thenReturn(mockPracticeSession)
    
            val mockiEbean = MockiEbean.start(dbmock)
            try{
                val practiceSessionDAO = PracticeSessionDAO()
                val practiceSession = practiceSessionDAO.getPracticeSession(1)
                assertEquals(1, practiceSession.id)
            } finally {
                mockiEbean.restoreOriginal()
            }
    
        }
    }