如何从.NET风格的TDD转向Ruby?

Dav*_*pak 9 .net c# ruby testing tdd

我一直在努力使我的标准方法适应测试驱动.NET代码到Ruby.

作为一个例子,我正在写一个类:

grab all *.markdown files from a directory
  foreach file:
    extract code samples from file
    save code to file.cs in output directory
Run Code Online (Sandbox Code Playgroud)

通常对于.NET,我最终会得到类似的东西:

class ExamplesToCode {
  public ExamplesToCode(IFileFinder finder, IExampleToCodeConverter converter) { ... }
  public void Convert(string exampleDir, string targetDir) { ... }
}
Run Code Online (Sandbox Code Playgroud)

在我的测试中(首先写的),我是模拟查找器和转换器.然后,我踩灭了finder.FindFiles("*.markdown")回说["file1", "file2"],检查converter.Convert("file1", targetDir)converter.Convert("file2", targetDir)被调用.

我努力将这个应用于Ruby的地方是Ruby倾向于使用块和内部迭代器(例如array.each { |x| puts x }),并且包括模块而不是构造函数注入.我不确定如何在这些情况下对代码进行单元测试(没有设置完整的集成测试),而且.NET方法看起来非常不完美; 它似乎与Ruby自然运作的方式作斗争.

有关如何以Ruby方式执行此操作的任何建议?这个例子的Ruby测试的例子很棒.

jta*_*ium 2

你可以进行一个非常简单的测试,如下所示:

class ExamplesToCodeTest < Test::Unit::TestCase
  def test_convert
    # have some example markdown files in a fixtures directory
    ExamplesToCode.convert("test/fixtures/*.markdown")
    assert_equal expected_output_1, File.read("test/output/file_1.cs")
    assert_equal expected_output_2, File.read("test/output/file_2.cs")
    assert_equal expected_output_3, File.read("test/output/file_3.cs")
  end
  private
    def expected_output_1
      "... expected stuff here ..."
    end
    def expected_output_2
      "... expected stuff here ..."
    end
    def expected_output_3
      "... expected stuff here ..."
    end
end
Run Code Online (Sandbox Code Playgroud)

我想这将是一个不错的集成测试,但这不是我真正喜欢的,我喜欢将我的代码分成小块

首先,我创建一个可以处理解析 markdown 文件的类,例如:

class MarkdownReaderTest < Test::Unit::TestCase
  def test_read_code_sample_1
    reader = MarkdownReader.new
    code_sample = reader.read("fixtures/code_sample_1.markdown")
    # or maybe something like this:
    # code_sample = reader.parse(File.read("fixtures/code_sample_1.markdown"))
    # if you want the reader to just be a parser...
    assert_equal code_sample_1, code_sample
  end
  # ... repeat for other types of code samples ...
  private
    def code_sample_1
      "text of code sample 1 here..."
    end
end
Run Code Online (Sandbox Code Playgroud)

现在读取和解析 Markdown 文件的所有代码都在 MarkdownReader 类中。现在,如果我们不想实际编写文件,您可以使用 RR 或 Mocha 或其他东西进行一些模拟(我在这里使用 rr ):

class CodeSampleWriter < Test::Unit::TestCase
  include RR::Adapters::TestUnit
  def test_write_code_sample
    # assuming CodeSampleWriter class is using the File.write()...
    any_instance_of(File) do |f|
      mock(f).write(code_sample_text) { true }
    end
    writer = CodeSampleWriter.new
    writer.write(code_sample_text)
  end
  private
    def code_sample_text
      "... code sample text here ..."
    end
end
Run Code Online (Sandbox Code Playgroud)

现在假设 ExamplesToCode 类使用 MarkdownReader 和 CodeSampleWriter 类,您可以再次将模拟对象与 RR 一起使用,如下所示:

class ExamplesToCodeTest < Test::Unit::TestCase
  include RR::Adapters::TestUnit
  def test_convert
    # mock the dir, so we don't have to have an actual dir with files...
    mock(Dir).glob("*.markdown") { markdown_file_paths }
    # mock the reader, so we don't actually read files...
    any_instance_of(MarkdownReader) do |reader|
      mock(reader).read("file1.markdown") { code_sample_1 }
      mock(reader).read("file2.markdown") { code_sample_1 }
      mock(reader).read("file3.markdown") { code_sample_1 }
    end
    # mock the writer, so we don't actually write files...
    any_instance_of(CodeSampleWriter) do |writer|
      mock(writer).write_code_sample(code_sample_1) { true }
      mock(writer).write_code_sample(code_sample_2) { true }
      mock(writer).write_code_sample(code_sample_3) { true }
    end
    # now that the mocks are mocked, it's go time!
    ExamplesToCode.new.convert("*.markdown")
  end
  private
    def markdown_file_paths
      ["file1.markdown", "file2.markdown", "file3.markdown"]
    end
    def code_sample_1; "... contents of file 1 ..."; end
    def code_sample_2; "... contents of file 2 ..."; end
    def code_sample_3; "... contents of file 3 ..."; end
end
Run Code Online (Sandbox Code Playgroud)

希望这能让您了解如何在 Ruby 中进行测试。不是煽动性的,但在大多数情况下,依赖注入并不是在 Ruby 世界中看到或使用的——它通常会增加很多开销。模拟/双打通常是更好的测试选择。