I'm working with a project which already has some legacy code written in Scala. I was given a task to write some unit tests for one of its classes when I discovered it's not so easy. Here's the problem I've encountered:
We have an object, say, Worker and another object to access the database, say, DatabaseService which also extends other class (I don't think it matters, but still). Worker, in its turn, is called by higher classes and objects.
So, right now we have something like this:
object Worker {
def performComplexAlgorithm(id: String) = {
val entity = DatabaseService.getById(id)
//Rest of the algorithm
}
}
My first though was 'Well, I can probably make a trait for DatabaseService with the getById method'. I don't really like the idea to create an interface/trait/whatever just for the sake of testing because I believe it doesn't necessarily lead to a nice design, but let's forget about it for now.
Now, if Worker was a class, I could easily use DI. Say, via constructor like this:
trait DatabaseAbstractService {
def getById(id: String): SomeEntity
}
object DatabaseService extends SomeOtherClass with DatabaseAbstractService {
override def getById(id: String): SomeEntity = {/*complex db query*/}
}
//Probably just create the fake using the mock framework right in unit test
object FakeDbService extends DatabaseAbstractService {
override def getById(id: String): SomeEntity = {/*just return something*/}
}
class Worker(val service: DatabaseService) {
def performComplexAlgorithm(id: String) = {
val entity = service.getById(id)
//Rest of the algorithm
}
}
The problem is, Worker is not a class so I can't make an instance of it with another service. I could do something like
object Worker {
var service: DatabaseAbstractService = /*default*/
def setService(s: DatabaseAbstractService) = service = s
}
However, it scarcely makes any sense to me since it looks awful and leads to an object with mutable state which doesn't seem very nice.
The question is, how can I make the existing code easily testable without breaking anything and without making any terrible workarounds? Is it possible or should I change the existing code instead so that I could test it easier?
I was thinking about using extending like this:
class AbstractWorker(val service: DatabaseAbstractService)
object Worker extends AbstractWorker(DatabaseService)
and then I somehow could create a mock of Worker but with different service. However, I didn't figure out how to do it.
I'd appreciate any advice as to how either change the current code to make it more testable or test the existing.
Aucun commentaire:
Enregistrer un commentaire