I've been in many situations where my core logic is in private methods. How would you go about unit testing that, is there any kind of compile time manipulation to ignore compile errors for unknown/private methods? I know that for the second part of the code I could use performSelector, but is that a reasonable solution?
For instance:
[[self.objectMock expect] privateMethod];
or
[self.object callPrivateMethodsToExpectSomeOtherBehaviour]
EDIT:
Here is an example to demonstrate why I feel like I need to test some private methods. Are these tests not reasonable? How else would I test that calling clear actually does what it suppose to do?
- (void)clear
{
self.orderNumber = nil;
[self.items removeAllObjects];
// Clear the rest of fields
}
- (void)testClearShouldRemoveOrderNumber
{
Order *order = [[Order alloc] init];
OCMockObject *orderPartialMock = [OCmockObject partialMockForObject:order];
[[orderPartialMock.items expect] setOrderNumber:nil];
[orderPartialMock clear];
[orderPartialMock verify];
}
- (void)testClearShouldRemoveItems
{
Order *order = [[Order alloc] init];
order.items = [[OCMockObject niceMockForClass:[NSMutableArray class]];
[[orderPartialMock.items expect] removeAllObjects];
[orderPartialMock performSelector@selector(clear)];
[orderPartialMock.items verify];
}
Methods are never "private" in the sense that once a class implements a method, it can be sent my anyone.
So, let's say you have a class Foo
with a "private" method bar
that is not in the interface declaration. You could, from anywhere, still invoke bar
though you may get a compiler diagnostic.
Probably the simplest approach is to declare the methods in a category that your tests use. For example:
@interface Foo (MyPrivateMethodsUsedForTesting)
- (void)bar;
@end
Now, you can use them without the compiler complaining either. Note, the methods do not have to be implemented in an actual MyPrivateMethodsUsedForTesting
category. This technique is also sometimes referred to as an "informal protocol."
EDIT
Also, as noted by others, that if you need to access private methods, you probably should revisit your design. After ~30 years doing this, there are definitely times where, especially for tests, you need to access private stuff, but most times it means some type of design review is in order.
You should not test your private methods directly. Instead, you need to test them through the public methods. Here is a link to a question on programmers.stackexchange.com discussing the matter.
The general idea of the answers is that you (or anyone else maintaining your code) should be free to change your private methods at any time by altering the signature, changing implementation, or removing them altogether. Nobody outside your class should care - after all, that's the primary driver behind making these methods private in the first place.
If you change your private method in an incompatible way, then unit tests of your public methods must break; otherwise, you didn't do a good job of testing your public methods. Effectively, this renders unit testing of private methods unnecessary.
In general you shouldn't need to unit test private methods.
The publicly exposed methods tell you what your class does - this is what you care about, and you should test these. The private methods are concerned with how your class does its job, your test shouldn't care about how the job gets done, as long as it gets done correctly.
If one day you decide to change how your class does its job (i.e. by changing the code in your private methods), without changing what your class actually does, then your unit tests should continue to pass. By trying to test the internals of your class you create a brittle test which may break even though the class is still working correctly.
If you are finding it difficult to test your class thoroughly by just using public methods then this is a warning sign that your class may be too big - consider breaking it up into smaller pieces.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With