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()
}
}
}
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()
}
}
}