- Czy taki kod Scali bez użycia DI z ręcznym tworzeniem operatorem new spotkaliście może kiedyś w aplikacjach webowych/mikroserwisach na produkcji w swoich projektach?
Tak, stosujemy właśnie takie DI bez magii.
- Czy raczej jesteście bardziej za użyciem lekkich frameworków typu Lagom/Play lub innych dla Scali zamiast ręcznego DI za pomocą new i SOLID? (Pisałem taki kod bez DI ale w Javie w projektach związanych z Big Data :D)
Rozwój Lagom i Play powoli jest przekazywany w ręce społeczności (bądź przechodzą one w tryb utrzymania), a Lightbend skupia się na Akce, która ma już sporo rzeczy analogicznych do tych z Playa i Lagoma. Polecam poczytać np. https://discuss.lightbend.com/t/on-the-future-of-akka-lightbend/8997/2
- Czy test integracyjny do LinkControllerSpec, który napisałem z pomocą Testcontainers jest ok według konwecnji pisania testów w Scali?
W sensie który aspekt mam ocenić? Na mongodb container się nie znam. Styl given-when-then sam wybrałeś, więc jeśli lubisz taki to ok.
Problem jest w kodzie poniżej, bo masz wyciek:
override def withFixture(test: OneArgTest): Outcome = {
val databaseName: String = "linkskap"
val mongoConnectionDetails: MongoConnectionDetails = MongoConnectionDetails(container.replicaSetUrl, databaseName)
val mongoConnectionProvider: MongoConnectionProvider = new MongoConnectionProvider(mongoConnectionDetails)
val linkPersistenceAdapter: LinkPersistenceAdapter = new LinkMongoAdapter(mongoConnectionProvider)
val linkFacade: LinkFacade = new LinkFacade(linkPersistenceAdapter)
val fixture: FixtureParam = FixtureParam(new LinkController(linkFacade))
super.withFixture(test.toNoArgTest(fixture))
}
Nie zamykasz połączenia. super.
nie jest potrzebne na końcu (bo wywołujesz przeciążoną metodę, a nie metodę z nadklasy). Coś takiego więc trzeba zrobić:
override def withFixture(test: OneArgTest): Outcome = {
val databaseName: String = "linkskap"
val mongoConnectionDetails: MongoConnectionDetails = MongoConnectionDetails(container.replicaSetUrl, databaseName)
val mongoConnectionProvider: MongoConnectionProvider = new MongoConnectionProvider(mongoConnectionDetails)
val linkPersistenceAdapter: LinkPersistenceAdapter = new LinkMongoAdapter(mongoConnectionProvider)
val linkFacade: LinkFacade = new LinkFacade(linkPersistenceAdapter)
val fixture: FixtureParam = FixtureParam(new LinkController(linkFacade))
try {
withFixture(test.toNoArgTest(fixture))
} finally {
klientOrazPołączenieDoMongosa.close()
}
}
Analogicznie trzeba zrobić w
before {
val mongoClient: MongoClient = MongoClient(container.replicaSetUrl)
val mongoDatabase: MongoDatabase = mongoClient.getDatabase("linkskap")
mongoDatabase.createCollection("links")
}
i wyjdzie:
before {
val mongoClient: MongoClient = MongoClient(container.replicaSetUrl)
try {
val mongoDatabase: MongoDatabase = mongoClient.getDatabase("linkskap")
mongoDatabase.createCollection("links")
} finally {
mongoClient.close()
}
}
Trochę dziwnie też wygląda hardkodowanie "linkskap" w BaseIntegrationSpec - tutaj bym się raczej spodziewał parametru niż sztywnej wartości. Ale może tak ma być.
Kolejna sprawa to to, że możesz stworzyć klasę bazową zamiast traita. Podobno szybciej się wtedy kompiluje, aczkolwiek nie mierzyłem:
https://www.scalatest.org/user_guide/defining_base_classes
Instead of duplicating code by mixing the same traits together repeatedly, we recommend you create abstract base classes for your project that mix together the features you use the most. For example, you might create a UnitSpec class (not trait, for speedier compiles) for unit tests that looks like (...)