How to test methods based on Salat with ScalaTest - scala

I'm writing a web-app using Play 2, Salat (for mongoDB bindin). I would like to test some methods, in the Lesson Model (for instance test the fact that I retrieve the right lesson by id). The problem is that I don't want to pollute my current DB with dummy lessons. How can I use a fake DB using Salat and Scala Test ? Here is one of my test file. It creates two lessons, and insert it into the DB, and it runs some tests on it.
LessonSpec extends FlatSpec with ShouldMatchers {
object FakeApp extends FakeApplication()
val newLesson1 = Lesson(
title = "lesson1",
level = 5,
explanations = "expl1",
questions = Seq.empty)
LessonDAO.insert(newLesson1)
val newLesson2 = Lesson(
title = "lesson2",
level = 5,
explanations = "expl2",
questions = Seq.empty)
LessonDAO.insert(newLesson2)
"Lesson Model" should "be retrieved by level" in {
running(FakeApp) {
assert(Lesson.findByLevel(5).size === 2)
}
}
it should "be of size 0 if no lesson of the level is found" in {
running(FakeApp) {
Lesson.findByLevel(4) should be(Nil)
}
}
it should "be retrieved by title" in {
running(FakeApp) {
Lesson.findOneByTitle("lesson1") should be(Some(Lesson("lesson1", 5, "expl1", List())))
}
}
}
I searched on the web but i can't find a good link or project that use Salat and ScalaTest.

Salat developer here. My recommendation would be to have a separate test only database. You can populate it with test data to put your test database in a known state - see the casbah tests for how to do this - and then test against it however you like, clearing out collections as necessary.
I use specs2, not scalatest, but the principle is the same - see the source code for the Salat tests.
Here's a good test to get you started:
https://github.com/novus/salat/blob/master/salat-core/src/test/scala/com/novus/salat/test/dao/SalatDAOSpec.scala
Note that in my base spec I clear out my test database - this gets run before each spec:
trait SalatSpec extends Specification with Logging {
override def is =
Step {
// log.info("beforeSpec: registering BSON conversion helpers")
com.mongodb.casbah.commons.conversions.scala.RegisterConversionHelpers()
com.mongodb.casbah.commons.conversions.scala.RegisterJodaTimeConversionHelpers()
} ^
super.is ^
Step {
// log.info("afterSpec: dropping test MongoDB '%s'".format(SalatSpecDb))
MongoConnection().dropDatabase(SalatSpecDb)
}
And then in SalatDAOSpec, I run my tests inside scopes which create, populate and/or clear out individual collections so that the tests can run in an expected state. One hitch: if you run your tests concurrently on the same collection, they may fail due to unexpected state. The solution is either to run your tests in isolated special purpose collections, or to force your tests to run in series so that operations on a single collection don't step on each other as different test cases modify the collection.
If you post to the Scalatest mailing list (http://groups.google.com/group/scalatest-users), I'm sure someone can recommend the correct way to set this up.

In my applications, I use a parameter in application.conf to specify the Mongo database name. When initializing my FakeApplication, I override that parameter so that my unit tests can use a real Mongo instance but do not see any of my production data.
Glossing over a few details specific to my application, my tests look something like this:
// wipe any existing data
db.collectionNames.foreach { colName =>
if (colName != "system.indexes") db.getCollection(colName).drop
}
app = FakeApplication(additionalConfiguration = Map("mongo.db.name" -> "unit-test"))

Related

Scala - ScalaTest: simulate input while testing

I've a application that's run on top of terminal.
This App uses only Scala and SBT and I'm testing it using ScalaTest.
I want to test all components like a integration test, running the app, but, for that, I want to simulate the user sending values via standard input using something like a robot. Most important of all, when I call readLine or readInt, I want to send differents values while testing.
Thanks in advance!
Edit 1
So, I've this code. It basically prints the options for the user. I want, for example, to send 1, and then 3,4, to create a new Cell and check my CellArray to check if a new cell was really created in that position.
do {
println("Select one of the options: \n \n");
println("[1] Make a cell alive");
println("[2] Next generation");
println("[3] Halt");
print("\n \n Option: ");
option = parseOption(readLine)
}while(option == 0)
option match {
case MAKE_CELL_ALIVE => makeCellAlive
case NEXT_GENERATION => nextGeneration
case HALT => halt
}
The general approach will be something along these lines.
// This is the class containing the logic you want to test
class MyInputThing {
def readInput() = readLine
def thingIWantToTest = {
val input = readInput
doStuffWithInput(input)
}
}
// This test class returns a value representing something you want to verify.
class TestMyInputThing extends MyInputThing {
override def readInput = "123"
}
Then, in your test, use TestMyInputThing.thingIWantToTest() and validate the response. You can also pull out readInput into a trait, parameterise the creation of TestMyInputThing, etc, in order to clean this up. I would also recommend looking into ScalaCheck so you don't need to handcode test scenarios.

How to initialize shared variables before parallel test in scalatest

I have scalatest codes like following:
class myTest extends FlatSpec with ParallelTestExecution {
val testSuiteId: String = GenerateSomeRandomId()
it should "print test id" in {
println(testSuiteId)
}
it should "print test id again" in {
println(testSuiteId)
}
}
The two tests cannot print the testSuiteId I generate before them. Instead they regenerate the ID and print it. I understand that because of ParallelTestExecution which extends OneInstancePerTest, each test here runs on its own instance and have a copy of the variable "testSuiteId".
But I do want a fixed Id for this test suite and each test case in this suite have access to this fixed it without modifying it. I tried to create the fixed id in BeforeAll{ } but still it didn't work.
How should I achieve what I want?
One way to work around it would be to put the shared state in some sort of external object:
object SuiteId {
lazy val id: String = GenerateSomeRandomId()
}
Admittedly this is very much a hack, and I wouldn't be surprised if scalatest has a way to handle this built-in which I am unaware of.

Slick codegen not giving any output

I am trying to use the current version of slick and slick-codegen (3.2.0) with a sqlite database. When I try listing the table, I get the names properly. However, when I try to generate classes corresponding to the tables, I do not get any output.
This works:
object TableCodeGenerator extends App
{
val db = Database.forURL("jdbc:sqlite:/home/samik/db/mydb.db", driver = "org.sqlite.JDBC")
val tables = Await.result(db.run(MTable.getTables), 1 second).toList
tables.foreach(println)
}
I get the output below:
MTable(MQName(models),TABLE,null,None,None,None)
MTable(MQName(users),TABLE,null,None,None,None)
However, the following code, run directly in the same way, doesn't work:
object TableCodeGenerator extends App
{
val db = Database.forURL("jdbc:sqlite:/home/samik/db/mydb.db", driver = "org.sqlite.JDBC")
val dbio = SQLiteProfile.createModel(Some(MTable.getTables))
val model = db.run(dbio)
val codegenFuture: Future[SourceCodeGenerator] = model.map(model => new SourceCodeGenerator(model))
codegenFuture.onSuccess
{
case codegen => codegen.writeToFile(
"org.sqlite.JDBC",
"/tmp",
"my.package.dao",
"Tables",
"Tables.scala")
}
}
Meaning, the code runs successfully, but I do not see any output file. Is there anything I am missing?
The above was happening because the underlying code was silently throwing an exception. The reason for this exception was that I was using a "feature" of sqlite where if you don't mention the datatype in schema, sqlite assumes it to be text type. However that creates a problem for the slick code.
More details here. The immediate solution was to fix the schema, but I think this has now been fixed in slick as well.

How to execute tests on the argument that a controller passes to the view in Play Framework

In our play application every controller function fetches data from the database (or some other way) and passes these values to the result
def index = Action { implicit request =>
val newsItems: List[String] = fetchNewsFromDB()
Ok(views.html.home.index(newsItems))
}
def fetchNewsFromDB() = List("Headline1", "Headline2")
I am writing tests using specifiactions (based on the documentation http://www.playframework.com/documentation/2.2.x/ScalaTest)
According to this documentation by controller as follows. In the next test I want to make sure that the index page contains a headline. I do this by checking if there exists a div with the class "headline"
"Example Page#index" should {
"should contain a headline" in {
val controller = new TestController()
val result: Future[SimpleResult] = controller.index().apply(FakeRequest())
val bodyText: String = contentAsString(result)
bodyText.toLowerCase must contain("<div class=\"headline\"")
}
}
However I would rather check whether the list newsItems which the controller passes to the view is nonempty.
What is the best way to do this?
Is it possible to this in a generic way for which little modification of the controllers is required?
I too was frustrated that I couldn't intercept the parameters on their way to the template - and in fact it can become extremely difficult to even get the template to render at all in tests if you have a lot of "state" in your pages (for example, implicits that provide the user object, navigation helpers etc).
What I ended up doing was putting in an extra "seam" for testability in my controllers; in my tests, I extend the controller under test, replacing the HTML rendering function with a mocked one, which I can then use to verify the parameters.
Here's a simple example based on your "news" Action; first, the controller, which is no longer an object so we can extend it:
object Application extends ApplicationController
trait ApplicationController extends Controller {
def newsAction = Action {
Ok(renderNews("this is the news"))
}
def renderNews(s:List[String]):Html = html.sandbox(s)
}
The renderNews method gives us the all-important "test seam". I think it also actually improves the readability of controller methods too, which is nice :-)
Now, the unit test:
class ApplicationSpec extends Specification with Mockito {
val mockedNewsRenderer = mock[List[String] => Html]
val controller = new ApplicationController {
override def renderNews(s:List[String]) = mockedNewsRenderer(s)
}
"Application News Controller" should {
"Pass a non-empty list of news items to the template" in {
val result = controller.newsAction(FakeRequest())
status(result) must beEqualTo(200)
val captor = ArgumentCaptor.forClass(classOf[List[String]])
there was one(mockedNewsRenderer).apply(captor.capture())
val theArgument = captor.getValue
theArgument.isEmpty must beFalse
}
}
}
We create a mock to stand-in for the renderNews function, extend the controller so that we can substitute it in (note that we don't change anything else about it of course), and then call the action as normal. Note that we still get a standard Play Result so we can still check status codes etc, but then, we can use the Mockito verify functionality that's built into Specs2, together with Mockito's ArgumentCaptor facility to assert that our template was indeed called, and that it was supplied with a non-empty list of strings.
This approach has worked well for me - it makes it possible to get really good code coverage of your controllers with fast-running and easy-to-write unit tests.
You have a very good question and a very valid point on testing controllers, but I'm afraid it can't be done easily. The problem is that the views compile to Scala functions meaning when you call views.html.home.index(newsItems) it will return an object of Html, which already has the Html put together and compiled. If you would like to test what get's passed in you need to intercept it before the view is called.
To solve this you would have to rewrite your controllers, by moving all your business logic out of the controller and only have the necessary request handling code there. That would almost be easier to test.

Scala drivers for couchdb and partial schemas

One question I have about current Scala couchdb drivers is whether they can work with "partial" schemas". I'll try to explain what I mean: the libraries I've see seem to all want to do a complete conversion from JSON docs in the database to a Scala object, handle the Scala object, and convert it back to JSON. This is is fine if your application knows everything about that type of object --- especially if it is the sole piece of software interacting with that database. However, what if I want to write a little application that only knows about part of the JSON object: for example, what if I'm only interested in a 'mybook' component embedded like this:
{
_id: "0ea56a7ec317138700743cdb740f555a",
_rev: "2-3e15c3acfc3936abf10ea4f84a0aeced",
type: "user",
profiles: {
mybook: {
key: "AGW45HWH",
secret: "g4juh43ui9hg929gk4"
},
.. 6 or 7 other profiles
},
.. lots of other stuff
}
I really don't want to convert the whole JSON AST to a Scala object. On the other hand, in couchdb, you must save back the entire JSON doc, so this needs to be preserved somehow. I think what I really what is something like this:
class MyBook {
private val userJson: JObject = ... // full JSON retrieved from the database
lazy val _id: String = ... // parsed from the JSON
lazy val _rev: String = ... // parsed from the JSON
lazy val key: String = ... // parsed from the JSON
lazy val secret: String = ... // (ditto)
def withSecret(secret: String): MyBook = ... // new object with altered userJson
def save(db: CouchDB) = ... // save userJson back to couchdb
}
Advantages:
computationally cheaper to extract only needed fields
don't have to sync with database evolution except for 'mybook' part
more suitable for development with partial schemas
safer, because there is less change as inadvertently deleting fields if we didn't keep up with the database schema
Disadavantages:
domain objects in Scala are not pristinely independent of couch/JSON
more memory use per object
Is this possible with any of the current Scala drivers? With either of scouchdb or the new Sohva library, it seems not.
As long as you have a good JSON library and a good HTTP client library, implementing a schemaless CouchDB client library is really easy.
Here is an example in Java: code, tests.
My couchDB library uses spray-json for (de)serialization, which is very flexible and would enable you to ignore parts of a document but still save it. Let's look at a simplified example:
Say we have a document like this
{
dontcare: {
...
},
important: "foo"
}
Then you could declare a class to hold information from this document and define how the conversion is done:
case class Dummy(js:JsValue)
case class PartialDoc(dontcare: Dummy, important: String)
implicit object DummyFormat extends JsonFormat[Dummy] {
override def read(js:JsValue):Dummy = Dummy(js)
override def write(d:Dummy):JsValue = d.js
}
implicit val productFormat = jsonFormat2(PartialDoc)
This will ignore anything in dontcare but still safe it as a raw JSON AST. Of course this example is not as complex as the one in your question, but it should give you an idea how to solve your problem.