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 2014-02-21 11:06
on 2014-02-21 23:48
On Feb 21, 2014, at 2:06, Sebastjan H. <firstname.lastname@example.org> 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 `` 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, `` passes.
on 2014-02-23 19:14
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