Where I struggle applying this to Ruby is that Ruby tends to use blocks and internal iterators (e.g. array.each { |x| puts x }), and including modules over constructor injection. I'm not sure on how to unit test code in those cases (without setting up a full integration test), and the .NET approach just seems incredibly un-rubyish; it seems to fight the way Ruby naturally works.

Any suggestions on how to do this the Ruby way? An example of a Ruby test for this example would be great.

Now all the code to read and parse markdown files is in the MarkdownReader class. Now if we don't want to have to actually write files you can get fancy and do some mocking with RR or Mocha or something (I'm using rr here):

Hopefully this gives you some ideas of how to approach testing in Ruby. Not be inflammatory, but for the most part, dependency injection is not something seen or used in the Ruby world -- it generally adds a lot of overhead. Mocking/Doubles are generally a much better option for testing.

Before answering the question on providing a way on how to do this in Ruby I'd like to clear up some misunderstandings.

Firstly, I would not say that there is a "Ruby way" of testings things like this any more than there is a strict way of testing something like this in .NET (which, admittedly I have not used for years). One could take an interaction-based (mocking) approach or, as you said, take more of a state-based approach by creating an integration test that exercises all three classes at once. The tradeoffs between the two approaches I think are language agnostic. Ruby hasmanymockingframeworks that would allow you to take an interaction-based approach if that is what you are most comfortable with. (I typically use the one that ships with RSpec.)

Secondly, I don't think "including modules over constructor injection" is an accurate statement. Modules are an extra tool available to you in Ruby but they by no means replace good OO design with object composition. I pass in dependencies to my initializers all the time in Ruby since it makes them easier to test and more reusable. I will generally default the dependency in the argument list however like so def initialize(converter=CodeConverter.new).

Now, to answer your question. What liammclennan said about using Dir::[] is correct- the finder is not needed. So the question is, how do you write tests for methods that calls Dir::[]? You have three options: 1) Use one of the above mentioned mocking libraries and stub Dir::[] (this is a simple and easy approach), 2) Write the files to disk and verify they are read (ick), or 3) Use a library like FakeFS to prevent disk IO but still allows you to write a natural looking test. The following example is one possible way of writing/testing this (using RSpec and FakeFS) that is somewhat parallel to your original design:

class CodeExtractor
def self.extract_dir(example_dir, target_dir)
Dir[example_dir + "/*.md"].each do |filename|
self.extract(filename, target_dir)
end
end
def self.extract(*args)
self.new(*args).extract
end
def extract(filename, target_dir)
# ...
end
end
# The spec...
require 'fakefs/spec_helpers'
describe CodeExtractor do
include FakeFS::SpecHelpers
describe '::extract_dir' do
it "extracts each markdown file in the provided example dir" do
FileUtils.touch(["foo.md", "bar.md"])
CodeExtractor.should_receive(:extract).with(Dir.pwd + "/foo.md","/target")
CodeExtractor.should_receive(:extract).with(Dir.pwd + "/bar.md","/target")
CodeExtractor.extract_dir(Dir.pwd, "/target")
end
end
describe '#extract' do
it "blah blah blah" do
# ...
end
end
end

Of course, there is the question of if such a test adds enough value to merit it's existence. I don't think I'll go into that though.... If you do decide to use FakeFS be aware that the stacktraces from errors can be non-helpful since the FS is faked out when RSpec tries to get the line number off the non-existent FS. :) Coincidently, I have some code that reads and parses markdown slides on github. The specs may serve as further examples of how you can approach testing things like this in Ruby. HTH, and good luck.

The original poster's comment about "including modules over dependency injection" is based on this article: fabiokung.com/2010/05/06/… So although you can still do DI through constructor, he saw merit in the module option presented in the article.
–
mkmurraySep 10 '10 at 18:37

Thanks Ben. Very helpful. While I wrote "the Ruby way", I really meant "a Ruby way". I realise there's lots of ways to do it, but some ways suit different platforms more than others.
–
David TchepakSep 11 '10 at 7:12

Out of all that pseudocode, the only thing that really worries me is "extracts code samples from file". Reading files from a directory is trivial, saving a file is trivial. Regardless of the test framework I'd spend most of my time focusing on the parsing bit.

For direct testing, I'd embed the snippets directly into the test case:

Derick mentions that in Ruby you don't have try as hard as other languages like C# to have your code be testable.

So maybe the answer is that your top-down BDD-like workflow that you picked up from J.P. Boodhoo's Nothing But .NET bootcamp http://jpboodhoo.com/training.oo doesn't apply in the same way you would in C#. Same would go for my little anagram code kata experiment I did on my blog a number of months back where I explored similar techniques in C# http://murrayon.net/2009/11/anagram-code-kata-bdd-mspec.html. I'm trying to figure out what this would mean...maybe you need to scrap the idea of the interfaces, because in Ruby you should do polymorphism via composition and not inheritance.