Dynamically change field values โ€‹โ€‹of a nested object

I am trying to write an integration test for my scala application (with akka-http ). I am facing a problem for which I cannot find a solution.

My Case classes are as follows:

 case class Employee(id:Long, name:String, departmentId:Long, createdDate:Timestamp) extends BaseEntity case class EmployeeContainer(employee:Employee, department:Department) extends BaseEntity 

I have such a method

 trait BaseTrait[E<:BaseEntity, C <: BaseEntity]{ def getById(id:Long): Future[List[C]] = { //query from db and return result. } def save(obj:E) = { //set the createDate field to the current timestamp //insert into database } } 

I can extend my class with BaseTrait and just override the getById () method. The remaining layers are provided by our internal infrastructure.

 class MyDao extends BaseTrait[Employee, EmployeeContainer] { override def getById(id:Long) = { for { val emp <- getFromDb(id) val dept <- DeptDao.getFromDb(emp.departmentId) val container = EmployeeContainer(emp,dept) } yield(container) } } 

So, in the rest of the layer, I get the answer as an EmployeeContainer . The problem I am facing is that the changed date is automatically updated with the current timestamp. Therefore, when I return the result, the timestamp in the object that I passed to the save () method will be overwritten by the current time. When I write a test case, I need to have an object for comparison. But the timestamp of this object and the one I get will never be the same.

In any case, in which I can replace the entire appearance of createDate with a known timestamp value so that I can compare it in my test folder? The main problem is that I cannot predict the structure of the container (it can have several classes of classes (nested or flat) with or without createDate fields).

I managed to replace the field with reflection if it is part of the main case class but is unable to execute for nested structures.

+5
source share
1 answer

You probably need to use some of Inversion of Control . The main problem is that you call db directly: val emp <- getFromDb(id) and, therefore, do not have control over checking the received values. Calling a database on a unit test is also a bad idea, as it extends the block to the entire database level. You want to test a small standalone unit.

A simple solution is to encapsulate database calls as an interface and transfer an instance of that interface. For instance:

  class MyDao extends BaseTrait[Employee, EmployeeContainer](val dbCall: Long => Employee) { override def getById(id:Long) = { for { val emp <- dbCall(id) val dept <- DeptDao.getFromDb(emp.departmentId) val container = EmployeeContainer(emp,dept) } yield(container) } } 

Then you can just use new MyDao(getFromDb) for regular code and val testDao = new MyDao(id => Employee(id, myFixedName, myFixedDeptID, myFixedTestDate)) from the test code.

0
source

All Articles