0

I created a Service Object (http://railscasts.com/episodes/398-service-objects), which basically creates two models, A and B, sets up the association between them where B belongs to A, and returns A (which in turn you can access B via A given the association).

On error, I return a hash with the error information. As I'm trying to test this method, I'm having an issue now where there are two possible types of returns: either a model (when it passes) or a hash with the error information.

Is this a signal that the design is wrong? I know when you test first (TDD) you avoid such design issues.

If it is an issue, then I know I would need to return an invalid A model. Assuming the model B throws an error on create, how would I still be able to return an invalid A model?

If returning an error hash is okay, how else can I design this method to be testing friendly?

darksky
  • 20,411
  • 61
  • 165
  • 254

2 Answers2

1

Good insight and good question. :-) On the face of it, this seems like a good situation to raise a Ruby exception for the "error" case rather than returning as a hash as a result of the method call. You can define your own error class (probably should be a subclass of StandardError) and include the hash or whatever information you want as part of the error you raise. See http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_exceptions.html for a discussion of this general topic.

As for checking for the raising of errors in rspec, see the last answer to How to use RSpec's should_raise with any kind of exception?, including links to additional information.

If you want to present your API as a RESTful interface, the consensus seems to be to utilize the HTTP response codes to be to present exceptions, as discussed in How to handle REST Exceptions? If you do use the exceptional response codes (e.g. 40X) for presenting your exceptions, then the fact that you return a hash in that case and a model in the other case is not a bad smell, imho, as there is no expectation of consistency between the data that accompanies an error and the data that accompanies a successful return. In any event, I don't think returning an "invalid" model in the error case makes any sense, assuming you're not in fact creating/persisting the model in that situation.

Community
  • 1
  • 1
Peter Alfvin
  • 28,599
  • 8
  • 68
  • 106
  • Thanks for your response. I am building an API and cannot afford to raise a Ruby exception/error as I will need to return the error gracefully to the user in JSON. What would you suggest in this case? – darksky Jul 16 '13 at 12:09
  • Yes I already do that in my controller. My service returns either a valid model (in which case the controller continues normally) or a hash representing an error (in which case throwing a HTTP response code error etc.). In that case, would it be okay for my service to return either a hash or a valid model, or should I try and see if I can return for example an invalid model? What if model B is the invalid one (see the above question again for B)? – darksky Jul 16 '13 at 12:49
  • See updated answer. Even if B is the invalid model, I still wouldn't return it, but instead return whatever information is necessary to appropriately describe the error. – Peter Alfvin Jul 16 '13 at 13:31
0

You can test the type of result.

In rspec...

expect(actual).to be_an_instance_of(expected)
expect(actual).to be_a_kind_of(expected)
SteveTurczyn
  • 36,057
  • 6
  • 41
  • 53