2015-07-02 2 views
5

Я пытаюсь написать интеграционный тест для моего приложения scalaakka-http). Я сталкиваюсь с проблемой, для которой я не могу найти решение.Динамическое изменение значений полей вложенного объекта

Мои классы Case, как показано ниже:

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

У меня есть метод, как этот

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 
    } 

} 

я могу расширить мой класс с BaseTrait и просто переопределить метод GetByID(). Остальные слои предоставляются нашей внутренней структурой.

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

Таким образом, в остальном слое, я буду получать ответ как EmployeeContainer. Проблема, с которой я сталкиваюсь, заключается в том, что измененная дата автоматически обновляется текущей меткой времени. Поэтому, когда я верну результат, метка времени в объекте, который я передал методу save(), будет перезаписана текущим временем. Когда я пишу тестовый пример, мне нужно иметь объект для сравнения. Но временная метка этого объекта и тот, который я получаю, никогда не будут прежними.

Есть ли в любом случае, в котором я могу заменить все события createDate на известное значение timestamp, чтобы я мог сравнить его в своей тестовой папке? Основная проблема заключается в том, что я не могу предсказать структуру контейнера (он может иметь несколько классов классов (вложенных или плоских) с полями createDate или без них).

Я смог заменить поле, используя reflection, если он входит в класс основного корпуса, но не может выполнить для вложенных структур.

ответ

0

Возможно, вам понадобится использовать для Inversion of Control. Основная проблема заключается в том, что вы вызываете db напрямую: val emp <- getFromDb(id) и, следовательно, не имеете контроля над проверкой полученных значений. Вызов БД на единичный тест также, возможно, является плохим, поскольку он расширяет блок до всего уровня базы данных. Вы хотите протестировать небольшую автономную единицу.

Простым решением является инкапсуляция вызовов БД в качестве интерфейса и передача экземпляра этого интерфейса. Например:

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

Тогда вы можете просто использовать new MyDao(getFromDb) для нормального кода и val testDao = new MyDao(id => Employee(id, myFixedName, myFixedDeptID, myFixedTestDate)) из тестового кода.

Смежные вопросы