当您需要探索代码时,如何进行单元测试?
在 TDD 中,当您知道最终结果应该是什么,但不知道实现该结果所需的处理步骤时,您应该如何继续?
例如,您的类正在传递一个对象,其 API 对您来说是全新的,您知道该类具有您需要的信息,但您还不知道如何检索它:您将如何测试它?
您是否只关注想要的结果而忽略了步骤?
编辑 1
package com.wesley_acheson.codeReview.annotations;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
public class AnnotationPresenceWarner implements AnnotationProcessor {
private final AnnotationProcessorEnvironment environment;
public AnnotationPresenceWarner(AnnotationProcessorEnvironment env) {
environment = env;
}
public void process() {
//This is what I'm testing
}
}
我正在尝试测试这个不完整的课程。我想测试我在 process 方法中与 AnnotationProcessorEnvironment 是否有正确的交互。然而,我从 API 文档中不确定什么是正确的交互。
这将生成一个文件,其中包含源树中每个注释出现的详细信息。
然而,实际的文件写入可能会委托给另一个类。因此,此类的职责是创建注释出现的表示并将其传递给需要移动它的任何类。
在非 TDD 中,我可能会调用一些方法设置断点并查看它们返回什么。
无论如何,我并不是在寻找这个特定示例的解决方案,更多时候,您不知道如何从 A 到 B,并且您希望测试驱动您的代码。
In TDD how should you continue when you know what your final outcome should be, but not the processing steps you need to get there?
For example your class is being passed an object whose API is completely new to you, You know the class has the information you need but you don't know how to retrieve it yet: How would you go about testing this?
Do you just focus on the desired result ignoring the steps?
Edit 1
package com.wesley_acheson.codeReview.annotations;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
public class AnnotationPresenceWarner implements AnnotationProcessor {
private final AnnotationProcessorEnvironment environment;
public AnnotationPresenceWarner(AnnotationProcessorEnvironment env) {
environment = env;
}
public void process() {
//This is what I'm testing
}
}
I'm trying to test this incomplete class. I want to test I have the right interactions with AnnotationProcessorEnvironment within the process method. However I'm unsure from the API docs what the right interaction is.
This will produce a file that contains details on the occurrence of each annotation within a source tree.
The actual file writing will probably be delegated to another class however. So this class' responsiblity is to create a representation of the annotation occurrences and pass that to whatever classes need to move it.
In non TDD I'd probably invoke a few methods set a breakpoint and see what they return.
Anyway I'm not looking for a solution to this specific example more sometimes you don't know how to get from A to B and you'd like your code to be test driven.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我的回答基于这个视频:
http://misko.hevery.com/2008/ 11/11/clean-code-talks-dependency-injection/
如果您有一个模型/业务逻辑类应该从服务中获取一些数据,那么我会这样做:
让您的模型类在构造函数中获取所需的数据,而不是服务本身。然后,您可以模拟数据并对您的类进行单元测试。
为服务创建一个包装器,然后您可以对包装器进行单元测试。
执行更全面的测试,实际将数据从包装器传递到模型类。
I'm basing my answer on this video:
http://misko.hevery.com/2008/11/11/clean-code-talks-dependency-injection/
If you have a model/business logic class that's supposed to get some data from a service then I'd go about this way:
Have your model class take the data that it needs in the constructor, rather than the service itself. You could then mock the data and unit test your class.
Create a wrapper for the service, you can then unit test then wrapper.
Perform a fuller test where you actually pass the data from the wrapper to the model class.
一般答案
TDD 可用于解决许多问题,首要的是确保代码更改不会破坏现有代码的预期行为。因此,如果您使用 TDD 编写了一个类,则首先编写一些代码,查看它是否失败,然后编写行为使其变为绿色,而不会导致其他测试变为红色。
编写测试用例的副作用是现在您有了文档。这意味着 TDD 实际上为两个不同的代码问题提供了答案。当学习一个新的 API 时,无论它是什么,您都可以使用 TDD 来探索它的行为(当然,在某些框架中这可能非常)。因此,当您探索 API 时,可以编写一些测试来为其使用提供文档。您也可以将这视为原型制作步骤,只是原型制作假设您在完成后将其丢弃。使用 TDD 方法,您可以保留它,因此您可以在学习 API 很久之后随时返回该方法。
给定示例的具体答案
有许多方法试图解决 AnnotationProcessor 的问题。有一个 断言框架,它通过在测试期间加载 java 代码并断言该行来解决该问题发生错误/警告。这里是堆栈溢出
General Answer
TDD can be used to solve a number of issues, the first and foremost is to ensure that code changes do not break existing code in regards to their expected behavior. Thus, if you've written a class with TDD, you write some code first, see that it fails, then write the behavior to make it green without causing other tests to become red.
The side-effect of writing the test cases is that now you have Documentation. This means that TDD actually provides answers to two distinct problems with code. When learning a new API, regardless of what it is, you can use TDD to explore it's behavior (granted, in some frameworks this can be very difficult). So, when you are exploring an API, it's ok to write some tests to provide documentation to it's use. You can consider this a prototyping step as well, just that prototyping assumes you throw it away when complete. With the TDD approach, you keep it, so you can always return back to it long after you've learned the API.
Specific Answer to the Example Given
There are a number of approaches which attempt to solve the problem with the AnnotationProcessor. There is an Assertion framework which addresses the issue by loading the java code during the test and asserting the line which the error/warning occurs. And here on Stack overflow
我会创建一个原型,而不进行测试来了解 API 的工作原理。当我明白这一点后,我将继续我的项目的 TDD 周期
I would create a prototype without the testing to get knowledge of how the api is working. When I got that understanding, I would continue on the TDD cycle on my project
我同意巴塞塔森的观点。首先进行一下测试,了解此外部 API 调用的作用以及您的方法需要什么。一旦您熟悉了 API,您就知道如何继续使用 TDD。
I agree with Bassetassen. First do a spike to understand what is this external API call does and what you need for your method. Once you are comfortable with the API you know how to proceed with TDD.
永远不要针对未知的 API 进行单元测试。如果您不拥有代码,请遵循相同的原则。将您正在编写的所有代码与未知或无主的代码隔离开来。
编写单元测试,就像
环境处理器
将是您稍后要使用 TDD 的代码一样。现在您可以遵循 @Tom 的建议,除了删除步骤 1。步骤 2 的单元测试现在只需将包装类的输出映射到对未知 API 的调用即可。第二步更像是集成测试。
我坚信将流程从 TDD 更改为原型设计再更改为 TDD 会造成速度损失。继续使用 TDD 直到完成,然后进行原型设计。
Never ever Unit Test against an unknown API. Follow the same principle is if you didn't own the code. Isolate all the code you are writing from the unknown or unowned.
Write your unit tests as if the
environmental processor
was going to be code that you were going to TDD later.Now you can follow @Tom's advice, except drop step 1. Step 2's unit tests now are just a matter of mapping the outputs of the wrapper class to calls on the API of the unknown. Step two is more along the lines of an integration test.
I firmly believe changing your flow from TDD to Prototyping to TDD is a loss in velocity. Stay with the TDD until you are done, then prototype.