The Crystal Programming Language Forum

Spec testing class using abort

Trying my first (very small) project, and of course I want to spec test it.

It’s a cli command, so I’ve factored out the main logic into a class for easy testing. But I would rather use the simple way of doing abort("missing argument") unless args.some_arg, as that one of the things I like about Ruby.

But how to handle this in a spec test? I’ve figured out that I can redefine abort() in my test, and do an assertion, but got kinda stuck on where to stick the message for inspection as there seems to be no such thing as global variables (or top level instance/class variables). But I might be barking up the wrong tree here.

What would be the most elegant way to test a class that calls abort() in some cases? Or do I have to translate it to an exception and catch that to do an abort in the main file wrapper?

That’s what I would do. Use exceptions in your main class, then catch those in the CLI wrapper file. E.g. oq/oq_cli.cr at master · Blacksmoke16/oq · GitHub. This way you can fully test the actual logic and not have to worry about doing hacky stuff to get around abort.

If you really wanted to test the abort logic too you could totally have your specs call the built binary and assert the output data/status is correct. E.g. oq/xml_spec.cr at dec9e0fce660f3f5dc30d2af5b46bbf5ee36d7cb · Blacksmoke16/oq · GitHub, where run_binary comes from oq/spec_helper.cr at dec9e0fce660f3f5dc30d2af5b46bbf5ee36d7cb · Blacksmoke16/oq · GitHub.

1 Like

Use exceptions in your main class, then catch those in the CLI wrapper file.

Yeah, I guess I’ll go with that. Gotta add a catchall for unexpected exceptions anyway.

Also means I wont have to figure out how to deal with abort()s non-returning nature. Hmm, I guess that’s also the answer to my question, overwrite abort() to throw a special exception and check for that in the spec. Doesn’t read as nice as actually using exceptions instead of abort, but it might be a trick handy for some other time.

If you really wanted to test the abort logic too you could totally have your specs call the built binary and assert the output data/status is correct.

Yeah, I’ve written Gherkin doing that in other languages. Quite nice when one can blackbox the entire command. But in this case I need to mock HTTP::Client for other tests, so I prefer moving a bit deeper in. But a single test that tests that does that to check that an exception ends in a non-zero exit code is in order.

I think the better solution is not to override abort but just raise an exception instead of calling abort.

But I usually wouldn’t bother about unit testing process exit behaviour. Having this covered in integration tests should be fine.