ruby-on-railsrubytestingrspecservice-object

Returning Invalid Models for Testing


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?


Solution

  • 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.