gpt4 book ai didi

actionscript-3 - 编写动态单元测试(flexunit)令人困惑。我如何使它更具模块化?

转载 作者:行者123 更新时间:2023-12-01 09:24:47 25 4
gpt4 key购买 nike

我一直潜伏在这里寻求帮助,现在我找不到当前问题的答案。

返回信息
我正在编写一些单元测试(是的!)。我有40个实现接口的对象。该接口中的一个函数接受两个参数,一个Rectangle和一个Rectangle数组:public function foobar(foo:Rectangle, bar:Array/*Rectangle*/):void;我想为这40个对象编写测试。为确保测试所有可能性,我需要在foo和bar(长度和内容)不同的地方进行测试。所以foo的x个数和foo中Rectangle的1个数。
每个实现该接口的对象都在运行一种算法,该算法将对bar中的每个Rectangle进行一些计算并更改其属性。每种算法都会产生截然不同的结果。
如果我选择有10个可能的foo对象,以及bar数组的10个可能的对象,我最终将写成千上万!测试。我不想手写数千个测试。

问题
对我而言,编写一个可以接收可能对象的算法,并对所有可能产生结果的可能配置进行欠缺测试的算法,是否会太落后?然后我返回并手动检查所有结果是否正确?这是进行单元测试的错误方法吗?
运行产生结果的算法是错误的,然后,手动检查输出?
我的另一种想法是,我向算法提供了可能的对象,并且它吐出了一些针对测试工具格式化的xml或json,然后我通过了每个测试,填写了缺少的断言值,然后通过它们来进行输入?
我的另一个计划是编写一种算法,该算法接受一个foo Rectangle列表和一个可能在bar中使用的Rectangle列表,并让该算法以与我的测试工具(包括断言)一起使用的格式生成JSON。由于产生JSON的算法不会知道这些断言,因此在通过测试工具将其发送之前,我会先将其写入。
这是常见的做法吗?

感谢您的任何反馈:)

最佳答案

给出一个好的答案并不容易,不知道有关您在实现中执行的计算类型的任何细节,但是我很佩服您愿意进行单元测试,所以无论如何我都会尽力而为,希望答案不会太长。 ;)

0.期望很高?

老实说,可能没有一个与您的问题完全相符的答案-许多方法可以正确完成工作,并且适用于单元测试的唯一基本规则是,它们应该可靠地帮助您证明您的系统是稳定的。如果他们不这样做,那么您就不必费心编写它们。但是如果可以做到这一点,可以通过创建具有一百万行不同输入和输出值组合的Excel工作表,然后将CSV格式的工作表馈送到单元测试中的for循环中来实现...

好的,也许有更好的方法。但是最终,这一切都取决于您要完成此操作的程度,以及您愿意为完成更好的测试而偏离所做的工作的程度。

1.准备一些聪明的评论

根据我在各行中所读到的内容,您没有花太多时间考虑可测试性,因为在编写测试之前已经编写了代码。可悲的是,这实际上并不是进行单元测试的最佳方法:添加到生产代码中的每一行都应始终在失败的单元测试中覆盖,甚至在编写它之前。只有这样,您才能始终确保系统正常运行-并且始终可以测试!听起来很累吗?一旦您习惯了,它就不是。

我不会在基础方面打扰您,但如果您真的很认真地对待单元测试,请让我建议您开始将TDD应用于所有 future 项目:首先,也许要观看cleancoders.com上的TDD情节-Bob叔叔这样做解释这些事情的方法比我做得更好,而且他很有趣(尽管他的演示是用Java编写的,但这不应该是个大问题-TDD的基本原理适用于所有语言)。

同时,我仍会根据您的问题做一些聪明的评论。告我 ;)

2.智能资产备注1:如何测试?

确保记住的测试目标是证明您正在测试的代码正确运行,而不是针对每种可能的参数组合重复进行验证。您应始终将断言的数量保持在最低限度,以证明您的代码正确。

然后,这将回答您的第一个问题:您应该只进行一次测试,以证明所测试的每种算法的正确性。输入和输出值的不同组合可用于该测试中的断言。

为每个算法添加更多测试的唯一原因是在测试失败时,即,如果将null作为参数传递,或者违反约束的任何事物都会发生什么。每次在发生故障时抛出错误时,都应在单独的测试中进行测试。

但是,更复杂的是选择开始编写测试的抽象级别。通常不必为类中的每个方法编写测试,尤其是对于私有方法。这是应用TDD的另一个原因-它使您可以从外部考虑要执行的操作,即您测试系统的一部分应该执行的操作,而不是测试每个实现细节。当您在编写代码之前进行测试时,很容易在这里和那里添加测试,因为您注意到程序已经扩展并且事情变得更加复杂。在“事后”执行此操作总是要困难得多。

3.智能资产注释2:要测试什么?

程序设计的目标应该是,使您的单元与系统的其他部分分离开,尽可能。这意味着将一个事物组合应用于一个单元中的另一个事物组合可能不是一个好的设计。您应该只能测试要在测试单元中实现的代码,并将其与所有其他内容分开。这表示

  • making sure each method you are testing does only one thing(!)和
  • 该方法所需的所有其他内容都必须作为参数传递,或作为字段变量提供给类-让我清楚一点:方法内不会创建任何对象,除非它们是临时变量或返回值!因此,在测试方法时,应使用test doubles替换外部依赖项。

  • 4.尝试将其应用于您的问题

    我为什么要告诉你这一切?在我看来,您的方法更像是 integration test:有一个黑匣子要测试,并且可能会产生无数个东西。这在某种程度上是可以的,但您仍应尝试使黑匣子尽可能小。

    现在,由于我对您正在执行的实际数学一无所知,因此从现在开始我将做一些假设。很抱歉,如果这些都不适合,但是如果您提供一些代码示例,我们将很高兴添加或更改信息。

    显而易见的第一个猜测:您正在根据 bar Rectangle的坐标值对 foo数组的所有成员重复应用相同的计算。这意味着您实际上在方法中做了两件事:a)遍历 bar数组,以及b)应用公式:
    public function foobar ( foo:Rectangle, bar:Array ) : void {
    for each ( var rect:Rectangle in bar) {
    // things done to rect based on foo
    }
    }

    在这种情况下,您可以轻松地改进体系结构。第一步是隔离公式:
    public function foobar ( foo:Rectangle, bar:Array ) : void {
    for each ( var rect:Rectangle in bar) {
    applyFooValuesToRect( foo, rect);
    }
    }

    public function applyFooValuesToRect ( foo : Rectangle, rect : Rectangle ) : void {
    // things done to rect based on foo
    }

    现在,您将看到真正应该测试的是 applyFooValuesToRect方法-突然使编写测试变得更加容易。

    我也可以想象一下迭代过程中可能会有变化:一种实现将 foo应用于所有 bar,一种匹配某些条件,仅应用于正匹配,也许一个基于每个 bar值对foo进行一系列计算,一个可以使用两个公式,而不是一个,等等。如果其中任何一个适用于您的项目,则可以使用 Strategy pattern极大地改善您的API,并降低复杂性。对于40个变体中的每个变体,将实际公式设为实现通用 Formula接口的单独类:
    public interface Formula {
    function applyFooToBar (foo:Rectangle, bar:Rectangle) : Rectangle;
    }

    public class FormulaOneImpl implements Formula {

    public function applyFooToBar (foo:Rectangle, bar:Rectangle) : Rectangle {
    // do things to bar
    return bar;
    }
    }

    public class FormulaTwoImpl implements Formula ... // etc.

    现在,您可以分别测试每个公式,并将断言应用于返回的值。

    您的原始类将采用 Formula类型的字段变量:
    public class MyGreatImpl implements OriginalInterface {
    public var formula:Formula;
    //..
    public function foobar (foo:Rectangle, bar:Array):void {
    for each (var rect:Rectangle in bar) formula.applyFooToBar (foo, rect);
    }
    }

    然后,您可以传入各种公式-只要它们实现接口即可。
    结果,您现在可以使用该接口来创建模拟对象,以测试算法的所有其他部分: Formula模拟对象所要做的就是验证是否调用了 applyFooToBar,并返回为每个断言设置的预定值。这样,您可以确保在测试数组的迭代时确实没有在测试公式。

    实际上,您也可以尝试将其应用于其他事物: CriteriaMatcher也是一种不错的策略,从...开始

    像这样分解代码时,您可能会发现有多个依赖同一公式的实现,但是迭代循环的变化有所不同,等等。它甚至可能使您减少实现的数量。您的初始界面-因为现在变体已封装到不同的策略类中。

    男孩,这是很长的文字。我现在停止咆哮。希望我能对此有所帮助-如果我的假设与我的假设相去甚远,请再次评论或编辑您的问题。也许我们可以缩小可能的解决方案的范围。

    关于actionscript-3 - 编写动态单元测试(flexunit)令人困惑。我如何使它更具模块化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9627483/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com