Test exceptions using espec in Elixir app - unit-testing

I'm just started to learn Elixir.
I'm trying to test exception with espec (https://github.com/antonmi/espec) and I stucked.
Here is my function
defp call_xml(request_body) do
resp = HTTPotion.post("http://foo.bar", [body: request_body, headers: ["Content-Type": "text/xml"]])
if resp.status_code in [200, 201] do
{:ok, elem(XMLRPC.decode(resp.body), 1).param}
else
raise AbpError, message: "Message body"
end
end
def create_some_stuff(a, b, c) do
req = %XMLRPC.MethodCall{method_name: "Foo.Bar",
params:[a, b, c]} |> XMLPRC.encode!
call_xml(req)
end
# tests
use ESpec
use HyperMock
import :meck
context "when exception rised" do
it "returns err message" do
# stubbed with :meck
expect(MyModule, : create_some_stuff, fn("foo", "bar", "baz") -> raise CustomError end)
expect(MyModule. create_some_stuff("foo", "bar", "baz")).to eq("???")
end # it
end
In that case I'm getting error raised in my expectation
** (AbpError) Error occured!
spec/lib/ex_abpclient_spec.exs:135: anonymous fn/7 in ExAbpclientSpec.example_returns_created_payback_eqcpjlrszudikwyovtmxbgfnha/1
(ex_abpclient) ExAbpclient.create_payment_payback("tr-TR", 10966, 10, "R", 495, 10, "DESC")
spec/lib/ex_abpclient_spec.exs:136: ExAbpclientSpec.example_returns_created_payback_eqcpjlrszudikwyovtmxbgfnha/1
(espec) lib/espec/example_runner.ex:33: ESpec.ExampleRunner.run_example/2
(elixir) lib/enum.ex:1088: Enum."-map/2-lists^map/1-0-"/2
(elixir) lib/enum.ex:1088: Enum."-map/2-lists^map/1-0-"/2
(espec) lib/espec/runner.ex:70: ESpec.Runner.run_examples/1
(espec) lib/espec/runner.ex:43: ESpec.Runner.do_run/2
How can I get stubbed exception?
Thanks in advance.
UPDATE
I tried to use HyperMock (https://github.com/stevegraham/hypermock) to stub the request, but with no luck too
context "when payback created" do
it "returns created payback" do
HyperMock.intercept do
request = %Request{body: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><methodCall>.....",
headers: ["Content-Type": "text/xml"],
method: :post,
uri: "http://foo.bar/webApiXmlRpcServlet"}
response = %Response{body: "fooooo", status: 500}
stub_request request, response
expect MyModule.create_some_stuff("a", "b", "c") |> to(raise_exception AbpError, "fooooo")
end
end # it
end # exception
Here is the result
/Users/retgoat/workspace/offside/ex_abpclient/spec/lib/ex_abpclient_spec.exs:135
** (AbpError) Error: "fooooo"
(ex_abpclient) lib/ex_abpclient.ex:55: ExAbpclient.call_xml/1
spec/lib/ex_abpclient_spec.exs:143: ExAbpclientSpec.example_returns_created_payback_nqfwohpurlvtzskdjxigeybamc/1
(espec) lib/espec/example_runner.ex:33: ESpec.ExampleRunner.run_example/2
(elixir) lib/enum.ex:1088: Enum."-map/2-lists^map/1-0-"/2
(elixir) lib/enum.ex:1088: Enum."-map/2-lists^map/1-0-"/2
(espec) lib/espec/runner.ex:70: ESpec.Runner.run_examples/1
(espec) lib/espec/runner.ex:43: ESpec.Runner.do_run/2
(espec) lib/espec/runner.ex:28: ESpec.Runner.handle_call/3
10 examples, 1 failures
Finished in 1.28 seconds (0.14s on load, 1.14s on specs)
Exception is rised, but I can't test it.

Roman!
You must pass a function to expect, not a result of a function call.
So, just wrap MyModule.create_some_stuff("a", "b", "c") by fn -> end like you do in the ExUnit expample:
elixir
it "raises exception" do
expect(fn -> MyModule.create_some_stuff("a", "b", "c") end)
|> to(raise_exception AbpError, "fooooo")
end

Related

How to test that private method is called using rspec

I'm trying to make sure that a given method is being called when called by a callback.
Basically, I have a RiskMatrix model, that calls 2 private methods on callback after_save
So I'm trying to test that those methods are properly called.
thanks a lot for your help
class RiskMatrix < ActiveRecord::Base
after_save :alert_admin, :save_suspicious_ip, if: proc {score.length >= ALERT_THRESHOLD}
private
def alert_admin
[...]
end
def save_suspicious_ip
[...]
end
end
risk_matrix_spec.rb
describe 'after_save' do
context 'score.length > ALERT_THRESHOLD' do
it 'should run alert_admin' do
matrix = build(:risk_matrix, score: 'ABCD')
expect(matrix).to receive(:alert_admin)
end
it 'should run save_suspicious_ip' do
matrix = create(:risk_matrix, score: 'ABCD')
expect(matrix).to receive(:save_suspicious_ip)
end
end
end
both tests fail
(#<RiskMatrix id: 3201, score: "ABCD", user_id: 3115, created_at: "2019-02-05 16:27:01", updated_at: "2019-02-05 16:27:01">).alert_admin(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
(#<RiskMatrix id: nil, score: "ABCD", user_id: nil, created_at: nil, updated_at: nil>).save_suspicious_ip(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
You can use shoulda-callback-matchers to test your callbacks
it { is_expected.to callback(:alert_admin).after(:save) }
The other way to test is verify that after save a matrix a suspicious_ip must exist.
let(:matrix) { create(:risk_matrix, score: 'ABCD') }
context "when score.length > ALERT_THRESHOLD" do
it "after create a matrix" do
expect(matrix.suspicious_ip).to_not be_nil
end
end
context "when score.length < ALERT_THRESHOLD" do
it "after create a matrix" do
expect(matrix.suspicious_ip).to be_nil
end
end
Maybe I am missing something but I am not seeing the save calls, have you tried:
it 'should run alert_admin' do
matrix = build(:risk_matrix, score: 'ABCD')
allow(matrix).to receive(:alert_admin)
matrix.save!
expect(matrix).to have_received(:alert_admin).once
end
Before you save you let RSpec know you gonna stub that method, after the save you verify the method was called.

How to extract messages using regex in Scala?

My version of RegEx is being greedy and now working as it suppose to. I need extract each message with timestamp and user who created it. Also if user has two or more consecutive messages it should go inside one match / block / group. How to solve it?
https://regex101.com/r/zD5bR6/1
val pattern = "((a\.b|c\.d)\n(.+\n)+)+?".r
for(m <- pattern.findAllIn(str).matchData; e <- m.subgroups) println(e)
UPDATE
ndn solution throws StackOverflowError when executed:
Exception in thread "main" java.lang.StackOverflowError
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4708)
.......
Code:
val pattern = "(?:.+(?:\\Z|\\n))+?(?=\\Z|\\w\\.\\w)".r
val array = (pattern findAllIn str).toArray.reverse foreach{println _}
for(m <- pattern.findAllIn(str).matchData; e <- m.subgroups) println(e)
I don't think a regular expression is the right tool for this job. My solution below uses a (tail) recursive function to loop over the lines, keep the current username and create a Message for every timestamp / message pair.
import java.time.LocalTime
case class Message(user: String, timestamp: LocalTime, message: String)
val Timestamp = """\[(\d{2})\:(\d{2})\:(\d{2})\]""".r
def parseMessages(lines: List[String], usernames: Set[String]) = {
#scala.annotation.tailrec
def go(
lines: List[String], currentUser: Option[String], messages: List[Message]
): List[Message] = lines match {
// no more lines -> return parsed messages
case Nil => messages.reverse
// found a user -> keep as currentUser
case user :: tail if usernames.contains(user) =>
go(tail, Some(user), messages)
// timestamp and message on next line -> create a Message
case Timestamp(h, m, s) :: msg :: tail if currentUser.isDefined =>
val time = LocalTime.of(h.toInt, m.toInt, s.toInt)
val newMsg = Message(currentUser.get, time, msg)
go(tail, currentUser, newMsg :: messages)
// invalid line -> ignore
case _ =>
go(lines.tail, currentUser, messages)
}
go(lines, None, Nil)
}
Which we can use as :
val input = """
a.b
[10:12:03]
you can also get commands
[10:11:26]
from the console
[10:11:21]
can you check if has been resolved
[10:10:47]
ah, okay
c.d
[10:10:39]
anyways startsLevel is still 4
a.b
[10:09:25]
might be a dead end
[10:08:56]
that need to be started early as well
"""
val lines = input.split('\n').toList
val users = Set("a.b", "c.d")
parseMessages(lines, users).foreach(println)
// Message(a.b,10:12:03,you can also get commands)
// Message(a.b,10:11:26,from the console)
// Message(a.b,10:11:21,can you check if has been resolved)
// Message(a.b,10:10:47,ah, okay)
// Message(c.d,10:10:39,anyways startsLevel is still 4)
// Message(a.b,10:09:25,might be a dead end)
// Message(a.b,10:08:56,that need to be started early as well)
The idea is to take as little characters as possible that will be followed by a username or the end of the string:
(?:.+(?:\Z|\n))+?(?=\Z|\w\.\w)
See it in action

Calling external services in scala code with dependencies

I am facing a major issue with my design at this juncture. My method is trying to accomplish the follows:
Insert the passed in object into the database.
Get the autoincremented id from the insert and use it to call webservice1 along with the object.
Get the result from webservice1 and call webservice2 with the original object and some response from webservice1.
Combine the results from webservice1 and 2 and write it into the database.
Get the resulting autoincremented id from the last insert and call webservice3 with the original object that would eventually result into the success or failure of the operation.
I want to design this in a flexible manner since the requirements are in a flux and I do not want to keep on modifying my logic based on any changing. I do realize some amount of change is inevitable but I would like to minimize the damage and respect the open-closed principle.
My initial take was as follows:
def complexOperation(someObject:T) =
dbService.insertIntoDb(someObject) match {
case Left(e:Exception) => Left(e)
case Right(id:Int) => webService.callWebService1(id,someObject) match {
case Left(e:Exception) => Left(e)
case Right(r:SomeResponse1) => webService.callWebservice2(r,someObject) match {
case Left(e:Exception) => webService.rollbackService1();Left(e)
case Right(context:ResponseContext) => dbService.insertContextIntoDb(context) match {
case Left(e:Exception) => Left(e)
case Right(id:Int) => webService.callWebservice3(id,someObject) match {
case Left(e:Exception) => webService.rollbackService3();Left(e)
case Right(r:Response) => Right(r)
}
}
}
}
As you can see, this is a tangled mess. I can neither unit test it, nor extend it nor very easily debug it if things spiral out of control. This code serves its purpose but it will be great to get some ideas on how I should refactor it to make the lives of the people who inherit my code a little more easier.
Thanks
Have a look at scala.util.Try. It's available in Scala 2.10, which may or may not be available to you as an option, but the idea of it is perfect for your scenario.
What you have in your code example is what I like calling the "pyramid" of nesting. The best solution to this is to use flat-mapping wherever you can. But obviously that's an issue when you have stuff like Either[Exception, Result] at every step. That's where Try comes in. Try[T] is essentially a replacement for Either[Exception, T], and it comes with all of the flatMap-ing goodness that you need.
Assuming you can either change the return type of those webService calls, or provide some implicit conversion from Either[Exception, Result] to Try[Result], your code block would become something more like...
for {
id <- dbService.insertIntoDb(someObject)
r <- webService.callWebService1(id,someObject)
context <- webService.callWebservice2(r,someObject)
id2 <- dbService.insertContextIntoDb(context)
response <- webService.callWebservice3(id,someObject).recoverWith {
case e: Exception => webService.rollbackService3(); Failure(e)
}
} yield response
Lift has a similar mechanism in net.liftweb.common.Box. It's like Option, but with a container for Exceptions too.
edit: It looks like you can use the left or right method of an Either, and it will let you use flatMap-ing almost exactly the way I described with Try. The only difference is that the end result is an Either[Exception, Result] instead of a Try[Result]. Check out LeftProjection for details/examples.
You can use for comprehension to reduce the noise in the code.
#Dylan had the right idea above. Let me see if I can help translate what you want to do into idiomatic Scala 2.9.1 code.
This version doesn't attempt any rollbacks:
// 1: No rollbacks, just returns the first exception in Left
def complexOperation1(someObject:T): Either[Exception, Response] = {
for {
id <- dbService.insertIntoDb(someObject).right
r <- webService.callWebService1(id, someObject).right
context <- webService.callWebservice2(idResp, someObject).right
id2 <- dbService.insertContextIntoDb(context).right
response <- webService.callWebservice3(id,someObject).right
} yield response
}
Now, let's try to do the rollbacks exactly as you had them above:
// 2: Rolls back all web services and returns first exception in Left
def complexOperation1(someObject:T): Either[Exception, Response] = {
for {
id <- dbService.insertIntoDb(someObject).right
r <- webService.callWebService1(id, someObject).right
context <- webService.callWebservice2(idResp, someObject).left.map { e =>
webService.rollbackService1()
e
}.right
id2 <- dbService.insertContextIntoDb(context).right
response <- webService.callWebservice3(id,someObject).left.map { e =>
webService.rollbackService3()
e
}.right
} yield response
}
If you define a function which does the effect (the rollback) on the left, it get's a little cleaner and easier to test, for example:
// 3: Factor out the side-effect of doing the follbacks on Left
def rollbackIfLeft[T](f: => Either[Exception, T], r: => Unit): Either[Exception, T] = {
val result = f
result.left.foreach(_ => r) // do the rollback if any exception occured
result
}
def complexOperation1(someObject:T): Either[Exception, Response] = {
for {
id <- dbService.insertIntoDb(someObject).right
r <- webService.callWebService1(id, someObject).right
context <- rollbackIfLeft(webService.callWebservice2(idResp, someObject),
webService.rollbackService1()).right
id2 <- dbService.insertContextIntoDb(context).right
response <- rollbackIfLeft(webService.callWebservice3(id,someObject),
webService.rollbackService3()).right
} yield response
}
You can try out rollbackIfLeft in the scala REPL to get a sense of it:
scala> rollbackIfLeft(Right(42), println("hey"))
res28: Either[Exception,Int] = Right(42)
scala> rollbackIfLeft(Left(new RuntimeException), println("ERROR!"))
ERROR!
res29: Either[Exception,Nothing] = Left(java.lang.RuntimeException)
Hope this helps!

Play 2.0 - mapping on a `map` or `for-yield` result in template

I want to perform two sequential map operations in Play 2.0 template. I have tried like this:
#defining(for(a <- as) yield { doSmthWith(a); doSmthWith2(a) })
{ aaas => aaas.map(_.toString).mkString("|") } /*CRASH*/
which I presume to be equivalent to regular Scala:
val aaas = for(a <- as) yield { doSmthWith(a); doSmthWith2(a) }
println(aaas.map(_.toString).mkString("|"))
but it crashes there on the first { saying expected start of definition...
Same thing as if I replace the for loop with regular map:
#(as.map(a => { doSmthWith(a); doSmthWith2(a) })).map(_.toString).mkString("|"))
With the same crash on the first } sign. How can I acheive sequentional mapping in a Play template?
UPDATE:
The stack - here it is! - right from the console:
sbt.PlayExceptions$CompilationException: Compilation error [expected start of de
finition]
at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$2$$anonfun$apply$
11$$anonfun$apply$12.apply(PlayReloader.scala:224) ~[na:na]
at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$2$$anonfun$apply$
11$$anonfun$apply$12.apply(PlayReloader.scala:224) ~[na:na]
at scala.Option.map(Option.scala:133) ~[scala-library.jar:0.11.2]
at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$2$$anonfun$apply$
11.apply(PlayReloader.scala:224) ~[na:na]
at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$2$$anonfun$apply$
11.apply(PlayReloader.scala:221) ~[na:na]
at scala.Option.map(Option.scala:133) ~[scala-library.jar:0.11.2]
The stack says smth about Option but I do not use them anywhere here. Must be some inner workings.
This works:
#defining(for (a <- List(1,2,3)) yield {
play.api.Logger.debug("a:" + a)
a*3
}) { as =>
#(as.mkString("|"))
}
Which displays 3|6|9 in the page and prints in the console:
[debug] application - a:1
[debug] application - a:2
[debug] application - a:3
So my guess is adding the # sign in front of the expression as well as putting the opening brace on the same line as the closing paren from defining would make it work (assuming doSmthWith2(a) actually returns something else than unit):
#defining(for(a <- as) yield { doSmthWith(a); doSmthWith2(a) }) { aaas =>
#(aaas.map(_.toString).mkString("|"))
}

Why does this mock 'return' a Closure as opposed to the actual return value?

I am mocking SearchableService in a Spock specification:
// In SearchControllerSpec:
def sControl = mockFor(SearchableService)
sControl.demand.suggestQuery { Map m -> 'suggested query string' }
controller.searchableService = sControl.createMock()
The code snippet under test looks as follows:
// In SearchController:
qSuggestion = searchableService.suggestQuery( query , allowSame:false)
// FAILS:
assert qSuggestion == 'suggested query string'
highlightedSuggestion = StringQueryUtils.highlightTermDiffs(query, qSuggestion)
The assertion fails - apparently due to the fact, that qSuggestion holds a closure as opposed to the defined string.
The final statement fails as highlightTermDiffs expects (String, String), but is getting (String, Closure).
What's wrong here? How can I correct the error?
You are calling suggestQuery(String, Map) but you are mocking suggestQuery(Map). Try
sControl.demand.suggestQuery { String query, Map m -> 'suggested query string' }