Cera
Cera

Reputation: 1909

How can I write Ruby unit tests for class definitions and so on?

Some of the key features in a library I'm writing revolve around what happens when you subclass some of the classes it provides.

I try to write unit tests before writing any actual code whenever I'm implementing a new feature. However, a lot of what I need to do is this sort of thing:

class Hand < FancyDocument
    push_to $handDB
end 
class Foot < FancyDocument
    push_to $footDB
end

One of the things I want to test is whether that class method works in the first place, before having methods that test whether instances of the class behave properly.

But in Ruby you can't define classes inside methods, so I don't know how to test this. I can just put them inside my test class and watch for whether an error is thrown, but this is not very elegant and throws away many of the advantages of using a proper test framework. And if I introduce some other code in the future that breaks this, it'll be less obvious exactly what broke and why.

Is there a way around this problem? Should I be using something other than the standard Test/Unit library?

Upvotes: 1

Views: 800

Answers (2)

Andrew Grimm
Andrew Grimm

Reputation: 81520

Can't define a class within a method? Of course you can! This is Ruby we're talking about!

class FancyDocument
end

def define_a_class
  Class.new(FancyDocument)
end

klass = define_a_class
klass.ancestors # => => [#<Class:0x10151fd90>, FancyDocument, Object, Kernel]

The only thing that's hard to define within a method are constants.

Edit: You can use const_set(string, value) to define a constant, and therefore make it a non-anonymous class. I'm not sure whether it's a good idea though.

Upvotes: 3

d11wtq
d11wtq

Reputation: 35308

I use RSpec, but the following would apply to any test framework. When I'm testing an abstract class, I try to isolate it as much as possible (and keep my fixtures clear), so I tend to create an anonymous subclass from it:

let(:document) { Class.new(FancyDocument) }

Class.new accepts a block if you need to add specific implementation to your fixture.

Upvotes: 1

Related Questions