I am trying out ScalaMock in my scala application
What i have is an RSSReader which reads data from XML using XML.load(<urlString>), like in the code below
class ScalaRssFinancialDataReader
....
def fetchRSS(url:String) = XML.load(url)
....
}
I am mocking it like this
"fetching global economics mocking XML trait" should "return data" in {
val xmlFragment = <item><title>foo</title><author>a</author></item>
val xmlMock = mock[scala.xml.XML]
val tradingEconomicsUrl = "http://www.tradingeconomics.com/russia/rss"
(xmlMock.load_).expects(tradingEconomicsUrl).returns(xmlFragment)
val rssReader = new com.worldcorpservices.rss.reader.ScalaRssFinancialDataReader()
val res = rssReader.fetchRssData("http://www.tradingeconomics.com/russia/rss", "RUSSIA")
assert(res.size() == 1)
}
the problem is that i keep on getting exception that 'XML is not part of p ackage scala.xml
What am i doing wrong here? is it possible to mock XML.load method?
kind regards
marco
scala.xml.XML is an object, Mockito cannot mock objects, you may want to check ScalaMock (expecially here) for that. What I usually do is create a test file and use that as test case, you don't really need to mock the method.
Check also this question and this question.
Related
I'm using other teams api(let's name it otherTeamAPI) to call data, so in my function, my code looks like this:
def getData(host:String, port:Int, date: String): Map[String, String] = {
val data = new otherTeamAPI(host,port)
val latestData = data.getLatestData(date)
}
Could someone teach me how to use Mockito to do the same thing to get data in unit test? I'm not sure whether to use something like below to new an api:
val otherTeamAPI = Mock[otherTeamAPI]
otherTeamAPI.getLatestData(date)
How to get data everytime i trigger my function getData? Do i need to do somthing new a mock otherTeamAPI?
Your code, written as is, is not testable. You have to be able to pass your method an instance of the OtherTeamAPI so that your production code uses a real instance but test code can use a fake one (a "mock").
How you pass this instance depends on the structure of the rest of your code: either as a parameter of this method getData or as an attribute of the class that contains it.
The first one would look like this:
def getData(api: OtherTeamApi, date: String): Map[String, String] = {
val latestData = api.getLatestData(date)
// ...
}
And then in your test, you can do something like:
val fakeApi = mock[OtherTeamAPI]
when(fakeApi.getLatestData(anyString())).the return(...)
val result = getData(fakeApi, ...)
// Then assert on result
This is a high level answer. You'll need to learn more about Mockito to find out what you want to do.
After Reading the official flink testing documentation (https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/stream/testing.html)
I was able to develop tests for a ProcessFunction, using a Test Harness, something like this:
pendingPartitionBuilder = new PendingPartitionBuilder(":::some_name", "")
testHarness =
new OneInputStreamOperatorTestHarness[StaticAdequacyTilePublishedData, PendingPartition](
new ProcessOperator[StaticAdequacyTilePublishedData, PendingPartition](pendingPartitionBuilder)
)
testHarness.open()
now, I’m trying to do the same for a ProcessAllWindowFunction, that looks like this:
class MapVersionValidationDistributor(batchSize: Int) extends
ProcessAllWindowFunction[MapVersionValidation, Seq[StaticAdequacyTilePublishedData],TimeWindow] {
lazy val state: ValueState[Long] = getRuntimeContext .getState(new ValueStateDescriptor[Long]("latestMapVersion", classOf[Long]))
(...)
First I realized I can’t use TestHarness for ProcessAllWindowFunction, because it doesn’t have a processElement method. In this case, what unit test strategy should I follow?
EDIT: At the moment my test code looks like this:
val collector = mock[Collector[Seq[StaticAdequacyTilePublishedData]]]
val mvv = new MapVersionValidationDistributor(1)
val input3 = Iterable(new MapVersionValidation("123",Seq(TileValidation(1,true,Seq(1,3,4)))))
val ctx = mock[mvv.Context]
val streamContext = mock[RuntimeContext]
mvv.setRuntimeContext(streamContext)
mvv.open(mock[Configuration])
mvv.process(ctx,input3,collector)
and I'm getting this error:
Unexpected call: <mock-3> RuntimeContext.getState[T](ValueStateDescriptor{name=latestMapVersion, defaultValue=null, serializer=null}) Expected: inAnyOrder { }
You don't really need test harness to unit test the process method of the ProcessAllWindowFunction. The process function takes 3 arguments: Context, Iterable[IN], Collector[OUT]. You can use some library depending on the language used to mock the Context. You can also easily implement or mock the Collector depending on your prerefences here. And the Iterable[IN] is just an Iterable containing the elements of Your window, that would be passed to the function after the window is triggered.
I am writing unit tests for Play application using Scalamock and Scalatest.
My original code looks like:
// Here ws is an injected WSClient
val req = Json.toJson(someRequestObject)
val resp: Future[WSResponse] = ws.url(remoteURL).post(Json.toJson(req))
In a part I have to mock external calls to a web service, which I am trying to do using scalamock:
ws = stub[WSClient]
wsReq = stub[WSRequest]
wsResp = stub[WSResponse]
ws.url _ when(*) returns wsReq
wsReq.withRequestTimeout _ when(*) returns wsReq
(wsReq.post (_: java.io.File)).when(*) returns Future(wsResp)
I am successfully able to mock post requests using a file, but I cannot mock post requests using JSON.
I tried putting stub function references separately like:
val f: StubFunction1[java.io.File, Future[WSResponse]] = wsReq.post (_: java.io.File)
val j: StubFunction1[JsValue, Future[WSResponse]] = wsReq.post(_: JsValue)
I get the compile error for second line: Unable to resolve overloaded method post
What am I missing here? Why cannot I mock one overloaded method but not the other one?
play.api.libs.ws.WSRequest has two post methods (https://www.playframework.com/documentation/2.4.x/api/scala/index.html#play.api.libs.ws.WSRequest), taking:
File
T (where T has an implicit bounds on Writeable)
The compiler is failing because you are trying to calling post with a single parameter, which only matches version 1. However, JsValue cannot be substituted with File.
You actually want to call the 2nd version, but this is a curried method that takes two sets of parameters (albeit the 2nd are implicit). Therefore you need to explicitly provide the mock value that you expect for the implicit, i.e.
val j: StubFunction1[JsValue, Future[WSResponse]] = wsReq.post(_: JsValue)(implicitly[Writeable[JsValue]])
Therefore a working solution would be:
(wsReq.post(_)(_)).when(*) returns Future(wsResp)
Old answer:
WSRequest provides 4 overloads of post method (https://www.playframework.com/documentation/2.5.8/api/java/play/libs/ws/WSRequest.html), taking:
String
JsonNode
InputStream
File
You can mock with a File because it matches overload 4, but JsValue does not match (this is part of the Play JSON model, whereas JsonNode is part of the Jackson JSON model). If you convert to a String or JsonNode, then it will resolve the correct overload and compile.
My best guess is that your WSRequest is actually a play.libs.ws.WSRequest which is part of the Java API, instead you should use play.api.libs.ws.WSRequest which is the Scala API.
The method WSRequest.post exists and BodyWritable[JsValue] is implicitly provided by WSBodyWritables in the Scala API but not in the Java API.
Another cause could be that your JsValue is not a play.api.libs.json.JsValue but something else (e.g. spray.json.JsValue).
I'll quote an example where I have successfully achieved what you are trying to do, the main difference is that I used mock instead of stub.
The important part is:
val ws = mock[WSClient]
val responseBody = "{...}"
...
"availableBooks" should {
"retrieve available books" in {
val expectedBooks = "BTC_DASH ETH_DASH USDT_LTC BNB_LTC".split(" ").map(Book.fromString).map(_.get).toList
val request = mock[WSRequest]
val response = mock[WSResponse]
val json = Json.parse(responseBody)
when(ws.url(anyString)).thenReturn(request)
when(response.status).thenReturn(200)
when(response.json).thenReturn(json)
when(request.get()).thenReturn(Future.successful(response))
whenReady(service.availableBooks()) { books =>
books.size mustEqual expectedBooks.size
books.sortBy(_.string) mustEqual expectedBooks.sortBy(_.string)
}
}
}
An you could see the complete test at: BinanceServiceSpec
I guess it should work fine, if you mock a response that is JsValue.
when(wsReq.post(Json.parse("""{...json request...}"""))).thenReturn(Future(wsResp))
Here Json.parse returns JsValue. Yo should pass the json string that you expect in the request body.
I'm trying to test the following line of code using ScalaTest and ScalaMock.
val responseFuture = wsClient.url(url).withQueryString(params: _*).get()
wsClient type is THttpClient, which is a wrapper of play.api.libs.ws.WS.
Given that:
val mockHttpClient = mock[THttpClient]
is properly injected into my class under test, the test code is something like this:
val expectedUrl = "some url"
val mockRequestHolder = mock[WSRequestHolder]
inSequence {
(mockHttpClient.url _).expects(expectedUrl).returns(mockRequestHolder)
(mockRequestHolder.withQueryString _).expects(where {
(parameters: Seq[(String, String)]) => {
// assertions on parameters
// ...
true
}
}).returns(mockRequestHolder)
val stubResponse = stub[WSResponse]
val jsonBody = "{}"
(stubResponse.json _).when().returns(Json.parse(jsonBody))
(mockRequestHolder.get _).expects().returns(Future(stubResponse))
}
IntelliJ is highlighting mockRequestHolder.get as an error saying: cannot resolve symbol get. Nevertheless I'm able to run the test but the mock is clearly not working, and I'm getting: java.util.NoSuchElementException: JsError.get.
The mock is working when I try to mock any other method of WSRequestHolder, but not with method get.
Is this a ScalaMock bug or am I doing something wrong?
I don't know if you have solved already the issue, but I have tried to do something similar recently and I kind of got it working with the following code:
val wsClientMock = mock[WSClient]
val wsRequestMock = mock[WSRequest]
val wsResponseMock = mock[WSResponse]
(wsRequestMock.withAuth _).expects(username, password, WSAuthScheme.BASIC).returning(wsRequestMock)
(wsRequestMock.get _).expects().returning(Future[WSResponse](wsResponseMock))
(wsClientMock.url _).expects(bootstrapUrl).returning(wsRequestMock)
(wsResponseMock.status _).expects().returning(200)
"kind of" because I need to mock also the response, otherwise I get results like
ERROR[default-akka.actor.default-dispatcher-4] OneForOneStrategy - Unexpected call: json()
due to the fact that the code calling the WSClient is calling the method .json of WSResponse.
Sorry, I don't know Scala Mock but I suggest you to have a look at MockWS a library which comes with a mocked WS client: play-mockws
With MockWS you define a partial function which returns an Action for a Route. This enables you to precisely configure mocked answers and test your http client code.
I've successfully used Specs2 to test serialization to a file, but the test uses a real file (written to /tmp/). I'd rather not touch disk just for a test. Is there a way to use a mocked file?
def serializeAndDeserializeFromDatafile[X <: CaseClass : Manifest](old: X, maybeGrater: Option[AvroGrater[X]] = None): X = {
val g = maybeGrater.getOrElse(grater[X])
//val outfile = mock[File]
val outfile = new File("/tmp/file1.avro")
g.serializeToDataFile(outfile, old) //Serialize to file
val infile = outfile
g.asObjectFromDataFile(infile) //Deserialize from file
}
I tried using Mockito to mock my outfile(the commented-out line above). In my naive attempt, I can create the Mock for File, hashCode: 1583021903, but it seems to be null when I try to serialize.
I think I'm missing a 'stub' of some sort, but I can't find any examples that are similar enough to suggest a solution. Any help would be appreciated.
I have a program (an autonomous written using Akka) that deals extensively in file system operations. I wrote it using ScalaIO (rather than native Java library java.io._ classes). ScalaIO includes, among other things, the RamFileSystem which allows you to mock file system contents and operations in ways that mirror real file system operations without involving file-system and I/O system calls.
You can mock out a File but that doesn't mean that things are going to work ok. By default, when you call a method on a mock, it returns null (or 0 for an int value for example).
So if the function you are testing calls one of the File methods you will need to provide sensible default values. For example:
val f = mock[File]
f.createNewFile returns true
f.isFile returns true
f.list returns Array("child1", "child2")
That being said, if your grater object really needs a functional file to write to, it might be impossible to really mock this.
Could you try use OutputStream/InputStream instead of files?
Example:
val out:OutputStream = null
// val testOut = new ByteArrayOutputStream()
// val realOut = new FileOutputStream(new File("/tmp/file1.avro"))
g.serializeToOutputStream(out, old) //Serialize to file
val in:InputStream = null
// val testIn = new ByteArrayInputStream(testOut.toByteArray)
// val realIn = new FileInputStream(new File("/tmp/file1.avro"))
g.asObjectFromInputStream(in) //Deserialize from file