如何有效地对动态语言的参数进行单元测试?
这个答案触动了我从未经历过的事情了解如何从 Java 处理动态语言与静态语言中的参数类型(我的观点是通知或变形 - 根据您的喜好)。
给定一个采用动态语言的参数 bar 的方法 foo,在编译时不会强制执行 bar 的类型。上面链接的答案(以及我通常看到的答案)是您需要使用动态语言正确进行单元测试。
但在某些时候,单元外部的某些东西会调用该方法。假设这是一个重量级对象,将在使用它的类的任何单元测试中进行模拟。现在你有很多类调用这个方法,你需要改变类型。为了简单起见,它过去需要一个数字,但现在需要一个字母数字,并且您需要使用专门适用于字符串的方法,而不是具有新要求的数字对象。
您如何更改它并知道调用代码将被修复?当然,如果您只是更改它,您的单元测试将会失败,但由于您需要故意更改它,所以表面上您会修复您的单元测试。你怎么知道要修复调用代码?我不仅仅是指您在概念上如何知道,我的意思是您如何知道您已找到所有呼叫者并且可以真正说它已更改。
似乎只有非常全面的集成测试才能给您这样的保证。我错过了什么吗?
This answer hit a nerve with me on something I have never understood with how you handle parameter types in dynamic languages vs. a static language (my perspective being informed or deformed - as you prefer) from Java.
Given a method foo that takes a parameter bar in a dynamic language, there is no enforcement at compile time of the type of bar. The answer linked above (and the answer I have generally seen to this) is that you need to unit test properly in a dynamic language.
But at some point something outside the unit will call that method. Say this is a heavy weight object that will be mocked in any unit tests of classes that use it. Now you have many classes which call this method, and you need to change the type. To keep it simple, it used to take a number, but now requires an alpha numeric, and you need to use a method specifically available on string and not on a number object with the new requirement.
How do you change it and know the calling code will be fixed? Sure if you just change it, your unit tests will fail, but since you need to change it on purpose, you would ostensibly fix your unit tests. How do you know to fix the calling code? I don't just mean how conceptually do you know, I mean how do you know you have found all the callers and can really say it is changed.
It would seem that only very comprehensive integration tests would give you that assurance. Am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为您已经给出了一个很好的具体示例来说明静态类型的优点之一。动态类型要求您自己找到所有这些调用位置。这实际上并不是很困难 - 它只是代码中的文本搜索。这就是权衡:编译器可以交叉引用您的代码并确保所有内容都匹配,而不是在整个代码中使用分散注意力的类型标签。
I think you've give an excellent concrete example of one of the advantages of static typing. Dynamic typing requires you to find all those call locations yourself. This is actually not very difficult though - its just a text search in your code. That's the trade-off: comfort that the compiler can cross-reference your code and make sure everything matches, vs not having distracting type tags throughout your code.
我需要 15 个字符才能发布,但答案是四个字符长:grep。
I need 15 characters to post, but the answer is four characters long: grep.
防御性编码。使更改在新方法中向后兼容。根据参数类型进行调度; CLOS 使这变得简单。
使用编辑器或 IDE 的“谁调用”功能。
Code defensively. Make the change backwards compatible in the new method. Dispatch on the type of the argument; CLOS makes this easy.
Use a "who calls" function of your editor or IDE.
这似乎更像是一个重构问题而不是单元测试问题。
通过确保特定函数中所需的所有属性和方法都存在并返回预期结果,对参数进行有效的单元测试。重要的是接口,而不是类型。
This seems to be more of a refactoring question than a unit test question.
Parameters are effectively unit tested by insuring all properties and methods that are needed in a particular function are present and return the expected result. It is the interface that matters not the type.
简而言之,答案就是“一直进行更多的单元测试”。
唯一重要的是新类型也具有所需的方法。因此,如果 ClassA 有 Method1(),它接受参数 obj 并调用 obj#M1() 和 obj#M2()< /code> - 对 obj 的唯一限制是它响应这些消息。如果您更改实现以调用以前不存在的方法
Foo()
,则执行 A 类的测试将失败。接下来,如果
ClassB
调用A#Method1()
作为其功能的一部分,并且 Class B 传递一个 obj(该对象确实具有所需的方法),则其测试将失败。如果 B 未实现所需的行为,则其测试应该失败,并且这应该直接导致 B 所需的更改。The short answer is just 'more unit tests all the way up'.
the only thing that matters is that the new type also has the methods required. So if
ClassA
has Method1() which takes a paramobj
and invokesobj#M1()
andobj#M2()
- the only constraint on obj is that it responds to these messages. If you change the implementation to invoke a methodFoo()
which did not exist previously`, the tests exercising Class A fail.Next if
ClassB
callsA#Method1()
as part of its functionality, its tests will fail if Class B is passing an obj, which does have the required methods. If the required behavior of B isn't achieved, its tests should fail and that should direct towards changes needed in B.动态语言开发人员需要复制静态类型的优势,即让工具能够自动发现这些错误。在大多数情况下,这涉及类型推断工具。推理本身相当困难(我正在撰写有关 PHP 推理的博士学位),但使用这些工具并不是非常困难。
有以下错误查找工具:
对于 PHP,phc 可以通过很少的工作量来完成此操作。
总的来说,当您没有静态类型时,您需要一个工具来获得好处。
Dynamic language developers need to replicate the advantages of static typing, that is, by having that tools can automatically find those errors. For the most part, this involves type inference tools. The inference itself is pretty difficult (I'm writing my PhD on doing it for PHP) but using the tools isn't terribly difficult.
There are error finding tools for:
For PHP, phc could do this with a very small amount of work.
Overall, when you don't have static typing, you need a tool to get the benefits.