Method invocation may produce 'NoMethodError' in Ruby - rubymine

I have some code:
# frozen_string_literal: true
require 'httpclient'
client = HTTPClient.new
response = client.get 'https://httpbin.org/get'
body = response.body
puts body
Why RubyMine have warning about Method invocation may produce 'NoMethodError'?

There's a corresponding issue on the RubyMine's tracker so you can follow it:
https://youtrack.jetbrains.com/issue/RUBY-24592

Basically, any object that doesn't respond to the method that's being invoked will raise a NoMethodError.
class Response
def body
'hardcoded body'
end
end
class ResponseWithoutBody; end
p Response.new.body
# "hardcoded body"
p ResponseWithoutBody.new.body
# `<main>': undefined method `body' for #<ResponseWithoutBody:0x00007fe903028e08> (NoMethodError)
In your case, if response returns nil, or any other object which doesn't implement body, then you're going to have a NoMethodError.
If you're pretty sure, you're never going to get nil after invoking get on client, then you can omit that warning message.

Related

Mocking Httpcalls always return NullPointerException

I'm trying to mock Http calls for unit test.
To do that I have done the following, I have created a RequestMock case class:
case class RequestMock() {
def sendRequest(httpRequest: HttpRequest)(implicit actorSystem: ActorSystem): Future[HttpResponse] = {
Http().singleRequest(httpRequest)
}
}
and in my service, I have written the following piece of code :
case class Service(requestHandler: RequestMock) {
....
for {
response <- {
requestHandler.sendRequest(
HttpRequest(
method = HttpMethods.GET,
uri = "http://database:9000"
)
)
} yield {
response
}
}
For the unit test, I'm trying to mock HttpCalls, to do that, I have done the following :
def test_2 = mock[RequestMock]
And for defining the mock behaviour I have done the following
when(test_2.sendRequest(
HttpRequest(
method = HttpMethods.GET,
uri = "http://database:9000")
)).thenReturn{
Future(
HttpResponse(
StatusCodes.OK,
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`,"connection established"))
But, when I execute unit tests, I always get the following error:
java.lang.NullPointerException
Does anyone know how I can solve this issue ?
A couple of problems.
First of all, test_2 should be a val, not a def.
With def like you have it, you get a different instance every time you access it. So, you define the stub on one instance, but then create your Service with a different one, that does not have sendRequest defined, so returns null by default, and that causes your NPE.
The next problem, that you will probably encounter after you fix this one is that you are not defining all of the behavior.
when(test_2.sendRequest(
HttpRequest(
method = HttpMethods.GET,
uri = "http://database:9000")
))
Only creates a stub for a method call with this specific parameter value. So, if your tests try to make a POST for example or hit a different endpoint, you'll get an NPE again.
Even if you only ever use one request, it is better to define the stub for any argument, to avoid weird NPE failures if the code happens to send a different one (you are writing a test, so should not just assume automatically, that the code will always do what you expect - you would not need the test in the first place if that was the case):
when(test2.sendRequest(any)),thenReturn(Future.successful(...))
(Note Future.successful above – that's the correct way to create Future that is immediately satisfied, what you are doing makes it run on a thread ... not a big deal in your case, but still icky).
Then, after the test code is run, you can check that the parameter value passed to the sendRequest was actually what you expect:
verify(test2)
.sendRequest(HttpRequest(method = HttpMethods.GET, uri = "http://database:9000"))

Implement custom assert for string matching

I'm implementing a unittest to check if certain strings in an application start with a legal prefix. For example as a test function body I now have:
strings_to_check = ['ID_PRIMARY','ID_FOREIGN','OBJ_NAME', 'SOMETHING_ELSE']
for s in strings_to_check:
assert s.startswith('ID_') or\
s.startswith('OBJ_')
But the AssertionError that is returned is quite verbose (the real code has more legal prefix option). I found this in the documentation, but that focusses on assertion between (custom) objects. Is there a way to write you own custom assertion function that returns a easier to read message?
You could do something like this:
def test_myex1(myfixture):
myfixture.append(1)
strings_to_check = ['ID_PRIMARY','ID_FOREIGN','OBJ_NAME', 'SOMETHING_ELSE']
for s in strings_to_check:
failing_string = f'variable s: {s} does not start with valid string'
assert s.startswith('ID_') or s.startswith('OBJ_'), failing_string
Which produces a traceback like:
> assert s.startswith('ID_') or s.startswith('OBJ_'), failing_string
E AssertionError: variable s: SOMETHING_ELSE does not start with valid string
raisetest.py:6: AssertionError

How Do I Attach A Body To a Delete in Dispatch?

I have a Dispatch 0.8 DELETE handler that needs to have a body.
So I have a normal DELETE that works fine:
def delete = request.DELETE ># identity
I tried this:
def delete(body: String) = request.DELETE <<< body ># identity
but it turned the request into a PUT because of the <<< operator.
Use setBody instead:
"If you wish to supply a string instead of a file, use a setBody method of the RequestBuilder class. Its variants support a number of input types and do not imply a particular HTTP method." from http://dispatch.databinder.net/HTTP+methods+and+parameters.html
To do this with Dispatch 0.8, I used a sort of hacky solution:
def delete(body: String) = (request << body).DELETE ># identity

How to get rid of the __actions__ entry in the CrudRestController's response?

I'm subclassing the CrudRestController to implement an REST interface. It works fine, but the response dict contains an __actions__ entry which contains some html code that I really don't want in my response.
According to the TableFiller class' docstring something like this should work:
class ProcessController(CrudRestController):
model = Process
#...
class table_filler_type(TableFiller):
__model__ = Process
__actions__ = False
But the page always throws an AttributeError: 'Process' object has no attribute '__actions__'
Any advice?
Despite the inline docs, the correct way seems to be:
class table_filler_type(TableFiller):
__model__ = Process
__omit_fields__ = ['__actions__', ]

Early return from a Scala constructor

I am writing the constructor for my "main" class. The first thing it does is call a method to use commons-cli to parse the command line. If the parseOptions method returns false, an error has occurred, and the constructor should exit.
I tried writing the following code
if (!parseOptions(args)) return
but the compiler complains that I have a "Return statement outside method definition".
Short of calling System.exit(1) or inverting the boolean (and putting all of the rest of my logic inside the if statement, is there any way to return "early" from a constructor?
I suppose I could have the parseOptions method throw an IllegalArgumentException and catch that in my Main object.
Thanks.
Dont try to do a early/premature return, this makes your code harder more complex, since the side effects of the return can be hard to understand. Instead use a exception to signal that something is wrong.
You can use require in the constructor. This doesn't return. But it seems like throwing an exception actually fits his situation better.
As in:
class MyTest(
private var myValue: Int ){
require(myValue > 0) // Connected to constructor
}
defined class MyTest
scala> val x = new MyTest(10)
x: MyTest = MyTest#49ff4282
scala> val y = new MyTest(-10)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:133)
is there any way to return "early" from a constructor
No. But in your case it sounds like bad design, anyway.
If the parseOptions method returns false, an error has occurred
In this case the constructor should throw an exception, not return normally.
A constructor should always either complete fully, or abort (throw an exception). Anything else leaves your object "half constructed" and thus impossible to reason about.
If in your case, the object is valid even if parseOptions failed, then you can change the condition and continue:
if (parseOptions(args)) {
// rest of constructor
}