Help with minitest - module testing

Hi,

I need advice and help regarding the testing with minitest(/spec). More
precisely I need help with testing the module methods. These are
basically blocks I’ve put in a module to organize my code. Following
some tutorials I’ve learned to test classes and their methods, but I’m
stuck with module methods.

I’m refactoring a program and I’m learning testing with minitest along
the way. My goal is to adopt the TDD or BDD style eventually. However
most of the code for this program is already in place. The program is a
computer aided translation tool, which stores translations in
YAML::Store file based databases. I use Shoes for the GUI.

As this is out of context, here are the variables definitions:

  1. tms_database: the database (YAML::Store) which holds all translation
    memories

  2. new_tm_name: the name of the new database which is an input from the
    user

  3. all_tms: the listbox (Shoes element) which holds all translation
    memories’ names from the tms_database

Here is the actual code snippet:

#module file: databases_module.rb

module DatabaseModule

class TranslationMemory
attr_accessor :name

def initialize(new_tm_name)
  @name = new_tm_name
end

end

def new_translation_memory(tms_database, new_tm_name, all_tms)
#create new translation memory
translation_memory = TranslationMemory.new(new_tm_name)

#store new translation memory
tms_database.transaction do
  tms_database[translation_memory.name] = translation_memory
end

# repopulate the listbox with all translation memories including the

newest one
tms_database.transaction(true) do
all_tms.items = tms_database.roots
end
end

end


#the spec file: databases_module_spec.rb

require ‘minitest/spec’
require ‘minitest/mock’
require ‘minitest/autorun’
require_relative “…/lib/WordFisher/databases_module”
include DatabaseModule

describe DatabaseModule do

describe “create new translation memory” do

before do
  @translation_memory = TranslationMemory.new("TM")
  @tms_database = MiniTest::Mock.new
  @tms_database.expect(:transaction,

DatabaseModule::TranslationMemory)
@all_tms = MiniTest::Mock.new
@all_tms.expect(:items, [“asdasdas”])
end

it "creates a new translation memory with a name" do
  @translation_memory.name.wont_be_empty
end

it "saves the new translation memory to DB for all database" do
  @tms_database.transaction do
    @tms_database[@translation_memory.name].must_be_kind_of
    DatabaseModule::TranslationMemory
  end
end

it "populates the array for all translation memories" do
  @all_tms.items.wont_be_empty
end

end

end

My question is what am I doing wrong? I know I must be doing something
wrong because the test pass even if I comment out the second and the
third part of the new_translation_memory method (ie: storing the new TM
and populating the listbox).
The overall question that bugs me, how to test these methods/blocks
which don’t get called on an object? I just pass them to the button:

button “New TM” do
new_translation_memory(tms_database, new_tm_name, all_tms)
end

thank you and kind regards,
seba

On Feb 21, 2014, at 2:06, Sebastjan H. [email protected] wrote:

My question is what am I doing wrong?

Easy: mocks. Explanation below.

before do
@translation_memory = TranslationMemory.new(“TM”)
@tms_database = MiniTest::Mock.new
@tms_database.expect(:transaction,
DatabaseModule::TranslationMemory)
@all_tms = MiniTest::Mock.new
@all_tms.expect(:items, [“asdasdas”])
end

Rule #1: fail FIRST. If you don’t fail, how do you ever know your test
even works?
Rule #2: mock LAST. Better yet, don’t mock at all if you can help it.

it “creates a new translation memory with a name” do
@translation_memory.name.wont_be_empty
end

This only tests that you wrote attr_accessor and hooked it up in the
initializer. Low value. Even lower that you’re only testing that the
value is non-empty. You could have returned [1] for all you know.

it “saves the new translation memory to DB for all database” do
@tms_database.transaction do
@tms_database[@translation_memory.name].must_be_kind_of
DatabaseModule::TranslationMemory
end
end

This just tests that you wrote a mock that returns transaction. Worse
yet, your mock returns a TranslationMemory and ignores your block
entirely. You can probably verify that via the assertion count.

it “populates the array for all translation memories” do
@all_tms.items.wont_be_empty
end

This just tests that you wrote a mock that returns items. Again, [1]
passes.

Hi,

thank you for the detailed feedback.

I have one additional question. I found a suggestion (for testing with
RSpec) that modules can be tested using dummy class which extends the
module to be tested.

Would this be better than mocks?

regards,
seba