I am having trouble writing unit test for the Dataset.map function for the below snippet, I am trying to write unit test using Flatspec and Matchers library
// Function within a Class
def dataValidation(ds: Dataset[someCaseClass]): Long = {
val validDs: Dataset[Booelan] = ds.map(entry => validate(entry))
validDs.filter(entry = !entry).count
}
def validate(data: someCaseClass): Boolean{
if(valid(data))
true
else
false
}
In the above code snippet I am facing hardtime in writing mock data for
val validDs: Dataset[Booelan] = ds.map(entry => validate(entry))
I get below error if I try to mock the map function as below
unit test code
when(
mock[Dataset[someCaseClass]].map(entry => validate(entry))
).thenReturn(mock[Dataset[Boolean]])
error that I get
SmartNull returned by this unstubbed method call on a mock:
dataset.map(
<function1>,
class[value[0]: boolean]
);
Related
I try to write a unit test for a small function in a controller using Play/ScalaTest+ Play. The function I want to test looks like this:
def functionToTest(id: String) = Action.async {
implicit request =>
lang
deeperFunction{ implicit context =>
...
}
}
The deeperFunction
def deeperFunction(block: Context => Future[Result])(implicit request: RequestHeader): Future[Result] = {
// returns Future.successful(Found("DummyUrltoRedirect"))
}
}
The deeperFunction is inherited from a trait and I don't want use the real one here because it's a unit test and so I want to use a matcher instead
val deeperMock = mock[Rainmaker]
val contextMock = mock[Context]
val controller = new Controller()(.....) // list of implicit arguments
"Controller" must {
"return something" in {
val request = FakeRequest("GET", "/something")
when(deeperMock.deeperFunction(anyObject)(anyObject)) thenReturn Future.successful(Found("DummyUrlToRedirect"))
val id = "id"
val result = controller.functionToTest(id).apply(request)
status(result) mustBe Ok
}
}
But when I run this, the line "val result = controller.functionToTest(id).apply(request)" still seems to call the real deeperFunction, not the fake one and therefore throws a null matcher at some point.
I also tried to use
when(controller.deeperFunction(anyObject)(anyObject)) thenReturn Future.successful(Found("DummyUrlToRedirect"))
instead, because the deeperFunction is inherited, but with the same result.
I tried to stick to theses instructions
ScalaTest+Play
dzone
but it seems I am still missing some basics/understanding. Thanks in advance.
I want to test my method which returns an Either. This is how i do this:
#Test def `Test empty name is not valid`: Unit = {
val book = createBook()
val result = insertEntryToBook(book, "", "12345")
result match {
case Left(InvalidNameFormat) => true
case _ => fail()
}
}
Should i do some assert() call instead of fail() to make the test's fail message more explicit (e.g. for assertion side-to-side view)?
There is no reason to pattern match here. You can just assert the result equals the expected value wrapped in a Left().
assertEquals(Left(InvalidNameFormat), result)
In case your test fails, you get a precise error message.
ScalaTest can be used with JUnit, so consider mixing in EitherValues which should give more informative messages
import org.junit.Test
import org.scalatest.{EitherValues, Matchers}
class ExampleSuite extends Matchers with EitherValues {
#Test def matchEithers(): Unit = {
val result: Either[String, Int] = Right(42)
result.left.value should be ("Boom")
}
}
which gives
org.scalatest.exceptions.TestFailedException: The Either on which left.value was invoked was not defined as a Left.
at org.scalatest.EitherValues$LeftValuable.value(EitherValues.scala:124)
at example.ExampleSuite.matchEithers(ExampleSuite.scala:9)
...
I'm implementing a Vault client in Scala using Http4s client.
And I'm now starting to write integration tests. So far I have this:
abstract class Utils extends AsyncWordSpec with Matchers {
implicit override def executionContext = ExecutionContext.global
implicit val timer: Timer[IO] = IO.timer(executionContext)
implicit val cs: ContextShift[IO] = IO.contextShift(executionContext)
val vaultUri = Uri.unsafeFromString(Properties.envOrElse("VAULT_ADDR", throw IllegalArgumentException))
val vaultToken = Properties.envOrElse("VAULT_TOKEN", throw IllegalArgumentException)
val clientResource = BlazeClientBuilder[IO](global)
.withCheckEndpointAuthentication(false)
.resource
def usingClient[T](f: VaultClient[IO] => IO[Assertion]): Future[Assertion] = {
clientResource.use { implicit client =>
f(new VaultClient[IO](vaultUri, vaultToken))
}.unsafeToFuture()
}
}
Then my tests look like this (just showing one test):
class SysSpec extends Utils {
"The auth endpoint" should {
"successfully mount an authentication method" in {
usingClient { client =>
for {
result <- client.sys.auth.create("test", AuthMethod(
"approle", "some nice description", config = TuneOptions(defaultLeaseTtl = 60.minutes)
))
} yield result should be (())
}
}
}
}
This approach works, however it doesn't feel right. For each test I'm opening the connection (clientResource.use) and recreating the VaultClient.
Is there a way for me to reuse the same connection and client for all the tests in SysSpec.
Please note these are integration tests and not unit tests.
This is the best I could come up with.
abstract class Utils extends AsyncWordSpec with Matchers with BeforeAndAfterAll {
implicit override def executionContext = ExecutionContext.global
implicit val timer: Timer[IO] = IO.timer(executionContext)
implicit val cs: ContextShift[IO] = IO.contextShift(executionContext)
val (httpClient, finalizer) = BlazeClientBuilder[IO](global)
.withCheckEndpointAuthentication(false)
.resource.allocated.unsafeRunSync()
override protected def afterAll(): Unit = finalizer.unsafeRunSync()
private implicit val c = httpClient
val client = new VaultClient[IO](uri"http://[::1]:8200", "the root token fetched from somewhere")
}
Then the tests just use the client directly:
class SysSpec extends Utils {
"The auth endpoint" should {
"successfully mount an authentication method" in {
client.sys.auth.create("test", AuthMethod(
"approle", "some nice description",
config = TuneOptions(defaultLeaseTtl = 60.minutes))
).map(_ shouldBe ()).unsafeToFuture()
}
}
}
My two main problems with this approach are the two unsafeRunSyncs in the code. The first one is to create the client and the second one to clean the resource. However it is a much better approach then repeatedly creating and destroy the client.
I would also like not to use the unsafeToFuture but that would require ScalaTest to support Cats-Effect directly.
While writing tests I'm confronted with the following exception:
java.lang.ClassCastException: codegen.java.lang.Object$MockitoMock$641592186 cannot be cast to cats.effect.IO (MyRepositorySpec.scala:19)
Which occurs when running this test code with specs2:
class MyRepositorySpec extends Specification with Mockito with TestData {
...
val m = mock[MyDAO[IO]].smart
m.createTable returns IO { Right[Throwable, Int](1) } // <- this is line 19
val r = new MyRepository[IO](m)
r.setup.unsafeRunSync() must beNone
...
}
MyDAO looks like this:
class MyDAO[M[_] : Monad](val transactor: Transactor[M])(implicit val AE: ApplicativeError[M, Throwable]) extends DataAccessObject[M, MyObject]
and the DataAccessObject like this:
trait DataAccessObject[M[_], T <: Entity]
I'm at a loss how to fix/correctly implement this. Any help would be appreciated. Thank you!
Try
class IOMyDAO(override val transactor: Transactor[IO]) extends MyDAO[IO](transactor)
val m = mock[IOMyDAO].smart
Based on this answer.
You should try to use org.mockito.Mockito#when instead of specs2s internal metod matching functionality:
when(m.createTable) thenReturn IO { Right[Throwable, Int](1) }
instead of
m.createTable returns IO { Right[Throwable, Int](1) }
I am having troubles getting my first Mock working in my Chat application using Mockito, I am trying to mock a Repository that takes a user ID as a string and returns all the conversations for this user. I am having a very hard time getting rid of a NullPointerException
Here is my Repository trait:
trait UserRepository {
val getConversations: (String) => Option[Vector[User]]
}
Here is my Service:
class UserService(userRepository: UserRepository){
private val boolToNumber : (Boolean) => Int = (bool) => ... not useful here
private val countToBool : (Int) => Boolean = (int) => ... not useful here
val getParticipations: (String) => Option[Vector[User]] = (name) => {
userRepository.getConversations(name) match {
... some implementation
}
}
And my tests
// init
val userRepository = mock[UserRepository]
// setup
when(userRepository.getConversations("Smith")) thenReturn (
Some(
Vector(
User("Smith", true, true, ConversationKey("Smith", "Smith and O'Connell chatroom")),
User("Smith", false, true, ConversationKey("Smith", "Smith and O'Connell chatroom"))
)
)
)
val userService : UserService = new UserService(userRepository)
// run
val actual = userService.getParticipations("Smith")
// verify
actual mustBe Vector(User("Smith", false, true, ConversationKey("Smith", "Smith and O'Connell chatroom")))
What I have tried so far:
printing after each operation in the tests, printing UserRepository returns Mock for UserRepository, hashCode: 1319190020, but the UserService is not printing so it is the one throwing the NullPointerException
changing "Smith" by the matcher any[String], same error, and
anyString same error
Wrapping String in a class called StringValue, same error Mockito
matchers
Change your val functions to def functions.
Im not too sure exactly why this is, but mockito is a java library so im not surprised that it doesnt handle scala function values well where Def's compile to the same thing as java methods.