I'd like to know the best way to approach testing ruby mixin modules, in this case for use with ActiveRecord models, but really this is a general quesiton that applies to any class that you are extending with a mixin.
我想知道测试ruby mixin模块的最佳方法,在本例中,用于ActiveRecord模型,但实际上这是一个通用的问题,适用于使用mixin扩展的任何类。
Is it better to attempt to stub all of the necessary functionality of the Class that your mixin is extending, or just test the real class as present and extended in your app?
尝试将mixin正在扩展的类的所有必要功能都存根化,还是仅仅在应用程序中测试实际的类?
Stubbing would remove external dependencies for the tests, but it fails to test the mixin under real circumstances. If the test fail, it could be either your implementation or the class you are extending that changed or broke. If testing with a stubbed class your tests may pass but the functionality could be broken if the class you are extending changes.
存根化将删除测试的外部依赖项,但它不能在实际情况下测试mixin。如果测试失败,可能是您的实现或正在扩展的类发生了更改或破坏。如果使用存根化的类进行测试,那么您的测试可能通过,但是如果您正在扩展的类发生更改,那么功能可能会被破坏。
Opinions?
意见吗?
1 个解决方案
#1
23
It's not completely clear to me what you're asking, but I'm going to assume it's something along the lines of, "If I have a class, and I extend that class with a module, where should I test the functionality provided by the module?"
我不完全清楚你在问什么,但我将假设它是类似的,“如果我有一个类,我用一个模块扩展这个类,我应该在哪里测试模块提供的功能?”
Personally, when I write a module for use as a mixin, I try to make sure it has fairly robust testing independent of whatever classes I might eventually plan to mix it in to. Typically I'll define a class in the test suite that does nothing but extend to module, and then write tests to ensure that the test class has all the expected functionality. (You can see examples of this in my Classy gem, which is just a collection of mixin modules.) If the module were meant to extend ActiveRecord or some other class I didn't have any control over, I'd define as vanilla an ActiveRecord class as possible and work with that, though ideally I'd try to keep my module's functionality orthogonal from ActiveRecord's when possible.
就我个人而言,当我编写一个作为mixin使用的模块时,我试图确保它具有相当健壮的测试,而不依赖于我最终可能计划将它混合到的任何类。通常,我将在测试套件中定义一个类,它除了扩展到模块之外什么都不做,然后编写测试以确保测试类具有所有预期的功能。(你可以在我的优秀gem中看到这样的例子,它只是mixin模块的集合。)如果这个模块是用来扩展ActiveRecord或者其他一些我没有控制的类,那么我就可以定义为vanilla一个ActiveRecord类,并且可以使用它,不过在理想的情况下,我应该尽可能保持模块的功能与ActiveRecord的正交。
If changes to ActiveRecord cause your tests to break, then there's a question of what your goals are in writing your module. If you want it to be generally available and useful to the public, then you probably want it to work with the newest version, and those failing tests are accurately reporting bugs that need fixing. If you only want it to work with whatever version you're running locally for your own project, then you can just run the tests against that version and you don't have to worry about it changing.
如果对ActiveRecord的更改导致您的测试失败,那么您在编写模块时的目标就是什么呢?如果您希望它对公众普遍可用并有用,那么您可能希望它与最新的版本一起工作,那些失败的测试准确地报告了需要修复的bug。如果您只想让它在本地为您自己的项目运行的任何版本中工作,那么您就可以针对该版本运行测试,而不必担心它的更改。
Assuming I had control over the class being mixed in to, I probably wouldn't test the functionality from the module too extensively in the tests for the class - that's what the module tests are for. I would have a test case or two to make sure that it generally works, and I would test any specific interactions or intricacies specific to the class being tested, and probably leave it at that.
假设我已经控制了类的混合,我可能不会在测试中对模块的功能进行太广泛的测试——这就是模块测试的目的。我将有一两个测试用例来确保它通常是有效的,并且我将测试任何特定的交互或对正在测试的类的复杂之处,并且可能将它放在那里。
#1
23
It's not completely clear to me what you're asking, but I'm going to assume it's something along the lines of, "If I have a class, and I extend that class with a module, where should I test the functionality provided by the module?"
我不完全清楚你在问什么,但我将假设它是类似的,“如果我有一个类,我用一个模块扩展这个类,我应该在哪里测试模块提供的功能?”
Personally, when I write a module for use as a mixin, I try to make sure it has fairly robust testing independent of whatever classes I might eventually plan to mix it in to. Typically I'll define a class in the test suite that does nothing but extend to module, and then write tests to ensure that the test class has all the expected functionality. (You can see examples of this in my Classy gem, which is just a collection of mixin modules.) If the module were meant to extend ActiveRecord or some other class I didn't have any control over, I'd define as vanilla an ActiveRecord class as possible and work with that, though ideally I'd try to keep my module's functionality orthogonal from ActiveRecord's when possible.
就我个人而言,当我编写一个作为mixin使用的模块时,我试图确保它具有相当健壮的测试,而不依赖于我最终可能计划将它混合到的任何类。通常,我将在测试套件中定义一个类,它除了扩展到模块之外什么都不做,然后编写测试以确保测试类具有所有预期的功能。(你可以在我的优秀gem中看到这样的例子,它只是mixin模块的集合。)如果这个模块是用来扩展ActiveRecord或者其他一些我没有控制的类,那么我就可以定义为vanilla一个ActiveRecord类,并且可以使用它,不过在理想的情况下,我应该尽可能保持模块的功能与ActiveRecord的正交。
If changes to ActiveRecord cause your tests to break, then there's a question of what your goals are in writing your module. If you want it to be generally available and useful to the public, then you probably want it to work with the newest version, and those failing tests are accurately reporting bugs that need fixing. If you only want it to work with whatever version you're running locally for your own project, then you can just run the tests against that version and you don't have to worry about it changing.
如果对ActiveRecord的更改导致您的测试失败,那么您在编写模块时的目标就是什么呢?如果您希望它对公众普遍可用并有用,那么您可能希望它与最新的版本一起工作,那些失败的测试准确地报告了需要修复的bug。如果您只想让它在本地为您自己的项目运行的任何版本中工作,那么您就可以针对该版本运行测试,而不必担心它的更改。
Assuming I had control over the class being mixed in to, I probably wouldn't test the functionality from the module too extensively in the tests for the class - that's what the module tests are for. I would have a test case or two to make sure that it generally works, and I would test any specific interactions or intricacies specific to the class being tested, and probably leave it at that.
假设我已经控制了类的混合,我可能不会在测试中对模块的功能进行太广泛的测试——这就是模块测试的目的。我将有一两个测试用例来确保它通常是有效的,并且我将测试任何特定的交互或对正在测试的类的复杂之处,并且可能将它放在那里。