【问题标题】:How much abstraction do I need for my code to be properly testable? [closed]我的代码需要多少抽象才能正确测试? [关闭]
【发布时间】:2021-03-25 11:54:16
【问题描述】:

我目前正在研究一种语言解释器,更具体地说,是研究该语言的数据模型,我的数据模型应该能够理解表达式并解释它们,例如:“cos(a + 4)”应该被解释为变量 a 中的值的余弦加 4,我将保留这个示例来解释我的工作原理。

我选择将表达式解释分解为多个步骤:

  1. 从表达式创建令牌列表,例如:cos(a + 4) 变为 [ "cos", "(", "a", "+", "4" ]
  2. 将数学运算符转换为函数,例如:[ "cos", "(", "a", "+", "4" ] 变为 [ "cos", "(", "sum", "(", "a", ",", "4", ")" , ")" ]
  3. 使用以下规则从此标记列表创建解析树:如果打开括号,则向下,如果关闭括号,则向上,如果逗号,则向右,否则将当前标记写入当前节点,例如: [ "cos", "(", "sum", "(", "a", ",", "4", ")", ")" ] 变成了这棵树:
    cos
      \
      sum
      / \
     a   4
  1. 使用解释树的递归函数

一切正常,但我希望我的代码能够得到很好的测试,我想知道我应该如何分离程序的类。

现在我将这个逻辑分为 2 个类,一个解析器执行前 3 个步骤,一个解释器执行最后一个步骤。

我是否应该将我的解析器分解为一个分词器、一个 operatorConverter 和一个 treeBuilder,以便将每个功能很好地分开并独立测试每个类,而不是让一个具有 3 个独立函数的解析器类作为解析器进行测试?

【问题讨论】:

    标签: c++ unit-testing


    【解决方案1】:

    这取决于实际代码和您的个人喜好。将解析器分成几个阶段或模块肯定会使测试和维护更容易。模块化对您来说有多大意义,除了您之外,任何人都无法回答。如果您选择了模块的粒度,结果发现它太粗粒度或太细粒度,您仍然可以稍后拆分或加入。

    【讨论】:

      【解决方案2】:

      我目前正在研究语言翻译。

      那么你应该阅读诸如the Dragon book、Queinnec 的Lisp In Small Pieces、Fowler 的Domain Specific Languages、Pitrat 的Artificial Beings, the conscience of a conscious machine、Parr 的The Definitive ANTLR 4 ReferenceGarbage Collection handbook 之类的书。

      一旦您阅读了几本书,请考虑使用解析器生成工具,例如 GNU bisonANTLR。还可以从ninjafishRefPerSysFLTKBismon 静态分析器、Frama-C 静态分析器等开源软件的源代码中寻找灵感。

      有关 RefPerSys 项目的问题,请通过电子邮件与我联系至basile@starynkevitch.net

      有关 Bismon 或 Frama-C 的问题,请通过电子邮件与我联系basile.starynkevitch@cea.fr

      考虑阅读ACM SIGPLAN 会议的会议记录。

      使用解释树的递归函数

      有时,该函数可能是 tail-recursive(而像 GCC 这样的良好优化 C++ 编译器可以将其编译为尾调用)。另一种方法是至少在书面英语中指定一些bytecode(就像Ocaml 解释器所做的那样),并将您的语言翻译成该字节码,然后编写您的字节码解释器。

      一旦你有一些错误的解释器,为它编写测试用例就是一件工作的事。学习GNU bash的源码,求灵感。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-24
        • 2017-07-27
        • 2013-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-19
        相关资源
        最近更新 更多