tags:

views:

55

answers:

3

I'm reading through the (still beta) rspec book by the prag progs as I'm interested in behavioral testing on objects. From what I've gleaned so far (caveat: after only reading for 30 min) the basic idea is that I want ensure my object behaves as expected 'externally' ie. in its output and in relation to other objects.

Is it true then that I should just be black box testing my object to ensure the proper output/interaction with other objects?

This may be completely wrong, but given all of the focus on how my object behaves in the system, it seems this is ideology one would take. If that's so, how do we focus on the implementation of an object? How do I test that my private method is doing what i want it to do for all different types of input?

I suppose this question is maybe valid for all types of testing?? I'm still fairly new to TDD and BDD.

+1  A: 

Yes, focus on the exposed functionality of the class. Private methods are just part of a public function you will test. This point is a bit controversial, but in my opinion it should be enough to test the public functionality of a class (everything else also violates the OOP principle).

Sven Koschnicke
ya i thought about the whole oo paradigm side of it. Of course it's a feature (whether good or bad) of ruby to be able to inspect inside our classes, but most languages don't even allow you to do that.
brad
+2  A: 

I think there are two issues here.

One is that from the BDD perspective, you are typically testing at a higher level than from the TDD perspective. So your BDD tests will assert a bigger piece of functionality than your TDD tests and should always be "black box" tests.

The second is that if you feel the need to test private methods, even at the unit test level, that could be a code smell that your code is violating the Single Responsibilty Principle and should be refactored so that the methods you care about can be tested as public methods of a different class. Michael Feathers gave an interesting talk about this recently called "The Deep Synergy Between Testability and Good Design."

Paddyslacker
BDD works at a unit level (with RSpec, in Ruby) as well as at an acceptance test level (with Cucumber). I tend to differentiate in the Java / C# worlds by calling them either Scenarios (acceptance tests) or Examples (unit tests). They should still be black box tests either way, but for different scales. If you're interested, Feature Injection takes BDD even further up into the analysis space...
Lunivore
Thanks for the clarification Liz - +1 for your comment! I like the "scenario" vs. "example" distinction. I'm tempted to edit my response to clarify that I'm talking about acceptance tests v. unit tests, but then the rest of this comment thread won't make sense. I think the second part of my answer is still very valid in terms of code smells.
Paddyslacker
+2  A: 

If you want to understand BDD better, try thinking about it without using the word "test".

Instead of writing a test, you're going to write an example of how you can use your class (and you can't use it except through public methods). You're going to show why your class is valuable to other classes. You're defining the scope of your class's responsibilities, while showing (through mocks) what responsibilities are delegated elsewhere.

At the same time, you can question whether the responsibilities are appropriate, and tune the methods on your class to be as intuitively usable as possible. You're looking for code which is easy to understand and use, rather than code which is easy to write.

If you can think in terms of examples and providing value through behaviour, you'll create code that's easy to use, with examples and descriptions that other people can follow. You'll make your code safe and easy to change. If you think about testing, you'll pin it down so that nobody can break it. You'll make it hard to change.

If it's complex enough that there are internal methods you really want to test separately, break them out into another class then show why that class is valuable and what it does for the class that uses it.

Hope this helps!

Lunivore
good answer! very concise!
brad