Hi all, I'm not to reading this list, so hopefully this isn't already
a well-known fact, but I wanted to share a trick that I spent a few
brain cells discovering:
I've been using Dr. Nic's rbiphonetest <
http://drnicwilliams.com/2008/07/04/unit-testing-iphone-apps-with-ruby-rbiphonetest/
> to write rspec specs and stories for an obj-c cocoa app. I came
across two problems when trying to use mock objects to test obj-c
classes.
1)
aMock = mock("a");
aMock.stub!(:methodThatReturnsInt).and_return(42);
In this case (and I don't claim to understand what's behind the
scenes), the 42 gets cast incorrectly when it's passed off to obj-c,
since rubycocoa thinks it's returning an object instead of an int.
The solution:
class MockA < OSX::NSObject
objc_method :methodThatReturnsInt, "i@:"
end
aMock = mock("a");
aMock.stub!(:methodThatReturnsInt).and_return(42);
2)
aMock = mock("a"); # This is a mock of an obj-c class, OSX::A
aMock.stub!(:methodThatReturnsInt).and_return(42);
OSX::MyObjCClass.alloc.init.doSomethingWithA(aMock);
This is only a problem if MyObjCClass has some logic in it that is
checking [aMock isKindOfClass:[A class]]. But here's a way to work
around it and make a Spec::Mocks object that obj-c thinks is a
subclass of MyObjCClass. The trick is to create a subclass of
MyObjCClass and then reimplement all it's methods to call
super.super.method so that the call will eventually get back to
Spec::Mocks' monkey-patching and our stubs and should_receive's will
work.
class MockA < OSX::A
def methodThatReturnsInt
return super.super.methodThatReturnsInt
end
end
aMock = mock("a");
aMock.stub!(:methodThatReturnsInt).and_return(42);
OSX::MyObjCClass.alloc.init.doSomethingWithA(aMock);
And now we can write specs for obj-c code that calls isKindOfClass: !
(Note that the previous objc_method trick is no longer necessary.)
===
That's all! I hope someone finds this interesting or useful. I'd
also appreciate any alternative suggestions from those who have inner
knowledge of rubycocoa or rspec.
Cheers,
--Aaron V.
|