【问题标题】:How to avoid re-testing the same behavior with unit test in javascript? (methods visibility and unit test)如何避免在 javascript 中使用单元测试重新测试相同的行为? (方法可见性和单元测试)
【发布时间】:2015-06-03 21:55:14
【问题描述】:

TDD原理:

  • 测试类的公共方法的行为。私有方法无论如何都要经过测试,因为公共方法调用了它们。不要测试私有方法。
  • 测试客户的预期行为,如 Sergey Berezovskiy 解释 here.

公平地说,这看起来非常好和简单。然而,在下面的例子中,这个原理导致对同一事物进行多次重新测试。这导致了top 5 TDD mistakes article. 中列出的第二和第三大错误,即“设置过多”和“断言过多”。

例子:

MyClass = function ()
{
    var self = this;    
    self.Tasks = [];
    self.IsExpanded = false;
    var _IsLoaded = false; 

    //Private
    function _LoadTasks()
    {
        //api call to load task
        _SortTasks();
    };

    //Private    
    function _SortTasks(tasks)
    {
        //Sort self.Tasks array
    };

    //Public    
    self.Method3 = function ()
    {
        //Do stuff
        if (HasDoneSomething)
        {
            _SortTasks();
        }
    };

    //Public    
    self.Method2 = function (param)
    {
        //Do stuff
        _SortTasks();
    }

    //Public    
    self.Method1 = function ()
    {
        if (self.IsExpanded)
            _Collapse();
        else
            _Expand();
    };

    //Private    
    function _Expand()
    {
        if (!_IsLoaded)
        {
            _LoadTasks();
        }
        self.IsExpanded = true;
    };

    //Private    
    function _Collapse()
    {
        self.IsExpanded = false;
    };
}

在上面的示例中,三个公共方法可能会影响任务的顺序。这导致对排序顺序的断言在多个测试中重复。

test("Some test 2", 2, function ()
{
    //Setup 
    var myClass = Builder.Build();

    //Action
    myClass.Method2(SomeParam);

    //Assertion
    ok( jobWasDoneProperly, "Task should now be started");
    ok( resuledSortIsGood, "Task started was moved after already started tasks and before unstarted ones");
});

test("Some test 3", 3, function ()
{
    //Setup 
    var myClass = Builder.Build();

    //Action
    myClass.Method3();

    //Assertion
    ok( taskLoadedCorrectly, "Tasks are loaded");
    ok( taskAreExpanded, "Tasks are expanded");
    ok( resuledSortIsGood, "Task started was moved after already started tasks and before unstarted ones");
});

对排序进行断言需要一些设置来验证结果排序。从而导致如前所述必须进行大量设置的错误。

问题可以通过测试“私有”方法“SortTasks”轻松解决。这样,我只能断言“SortTask”是用间谍调用的,而不是在“method1”、“method2”和“method3”的测试中实际测试结果排序。这不会减少断言计数,但确实减少了很多设置的长度,因为需要较少的验证。但是,这表明代码中有异味,因为它违反了 TDD 原则。

在 c# 中,一种解决方法 是创建一个继承 List 的新类名“TaskList”。对其实施公共排序方法。然后使用这个类来保存“MyClass”中的“Tasks”而不是一个数组。这样,我们就不会违反“不测试私有方法”的规则,一切都会很好。但我在 javascript 中,我的数组实际上是一个 Knockout obserbaleArrays, 我简要检查了是否可以在 javascript 中继承数组。这似乎是可能的,但我对去那里不感兴趣,因为它似乎根本没有内置并且太复杂了。我不想维持这样的事情。

在尊重“不测试私有方法”规则的同时测试这个问题的排序的正确方法是什么?

【问题讨论】:

    标签: javascript unit-testing tdd


    【解决方案1】:

    首先,在 TDD 中,与您的代码量相比,测试量是不够的。 对于这么多的代码,你可能会得到 200 多行测试。

    你说得对,在 C# 中你会从列表继承,而不是你可能会通过构造函数注入它。你可以很容易地用间谍做到这一点。

    你应该测试整个 SUT 的结果,所以如果你的 sut 正在做某事,并且它对实现它的东西进行排序,你不应该测试排序 - 或者传递一个间谍来看看会发生什么。

    您还可以轻松实现“私有”功能

    MyClass = function(){
     _function privateFunc(){}
    }
    

    现在你无法从外部访问它

    另外,如果你是 JS 新手,我建议你试试 jasmine 进行测试,它非常适合 C# 开发人员

    【讨论】:

    • 好的,我将在另一个主题中了解如何使我的函数真正私有化。谢谢,将尝试您的解决方案。我已经使用 QUnit 进行测试,使用 Sinon 来监视、存根和模拟事物。到目前为止,它确实有效。就像我说的,如果我将我的排序方法公开,我可以单独测试排序并测试排序是否被调用。这样我测试了整个 SUT。但这样做时,我通过低音绕过了排序的私有可见性。
    • 还有关于 200 行以上的测试代码,这是一个缩小版的测试,只是为了解释我的意思。您的回答让我意识到我的问题并不简单,所以我编辑了我的问题以澄清。现在应该很清楚,您应该能够相应地更新您的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 2017-12-01
    相关资源
    最近更新 更多