TDD:为什么让应用程序代码知道它正在测试而不是运行可能是错误的? [英] TDD: why might it be wrong to let app code know it is being tested, not run?

查看:62
本文介绍了TDD:为什么让应用程序代码知道它正在测试而不是运行可能是错误的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此线程中,布莱恩(唯一的回答者)说您的代码应以与测试无关的方式编写"

In this thread, Brian (the only answerer) says "Your code should be written in such a fashion that it is testing-agnostic"

一条评论说:您的代码绝对不应在全局我正在测试的标志"上分支."

The single comment says "Your code should definitely not branch on a global "am I being tested flag".".

但都没有给出原因,我会真的希望听到一些对此事的理性思考.进入一个给定的应用程序类并设置一个布尔值以表示这是一个测试,而不是运行",这将是非常容易的(特别是考虑到许多测试具有对应用程序类的程序包私有访问权限的事实).

But neither gives reasons, and I would really like to hear some rational thoughts on the matter. It would be immensely easy (particularly given the fact that a lot of tests have package-private access to the app classes) to reach into a given app class and set a boolean to say "this is a test, not a run".

我发现自己跳进篮球圈(注入模拟的私有字段等)来实现的各种事情可能变得更容易实现.

All sorts of things which I find myself jumping through hoops (injected mocked private fields, etc.) to achieve could become easier to accomplish.

很明显,如果走得太远,可能会造成灾难性的后果……但是作为软件测试库中众多工具中的一种工具,为什么这个概念会遇到这种麻烦呢?

It's also obvious that if you took this too far it could be disastrous... but as one tool among many in the software testing armoury why does the concept meet with such opprobrium?

密克助记符的答案:

一个简单的例子可能会有所帮助,如果您实际上是在方法中间创建一个新的类实例并将其分配给私有字段:在这种情况下,私有字段模拟将无济于事,因为您是替换私有字段.但是实际上创建一个真实的对象可能会非常昂贵:您可能需要在测试时将其替换为轻量级版本.

A trivial example of how this might help would be if you're actually creating a new class instance in the middle of a method and assigning it to a private field: private field mocks won't help in that case because you are replacing the private field. But actually creating a real object might be very costly: you might want to replace it with a lightweight version when testing.

实际上,昨天我遇到了这种情况……我的解决方案是创建一个名为createXXX()的新程序包专用方法...以便我可以对其进行模拟.但这反过来反驳了这样的格言:您不能创建仅适合您的测试的方法"!

I encountered such a situation yesterday, in fact... and my solution was to create a new package-private method called createXXX()... so I could mock it. But this in turn goes against the dictum "thou shalt not create methods just to suit your tests"!

推荐答案

我将这个答案分为两部分.首先,我将分享我对Brian答案的看法,然后,我将分享一些有关如何有效测试的提示.

I will split this answer into two sections. First I'll share my thoughts on Brian's answer, then I'll share some tips on how to test effectively.

Brian暗示了两个关键思想.我将分别针对每个人.

There appear to be two key ideas that Brian is hinting at. I will address each one individually.

您的代码应以与测试无关的方式编写.

Your code should be written in such a fashion that it is testing-agnostic.

生产代码取决于测试.应该是相反的.

The production code should not depend on tests. It should be the reverse.

有多种原因:

  1. 更改测试将不会更改代码的行为.
  2. 您的生产代码可以独立于测试代码进行编译和部署.
  3. 更新测试时,您的代码不需要重新编译.
  4. 由于未运行测试代码而产生的意外副作用,您的生产代码不可能失败.
  1. Changing your tests will not change the behaviour of your code.
  2. Your production code can be compiled and deployed independently of the test code.
  3. Your code won't need to be recompiled when updating the tests.
  4. Your production code cannot possibly fail due to unintended side effects from not running the test code.

注意:任何体面的编译器都将删除测试代码.尽管我认为这不是设计/测试系统不当的借口.

Note: Any decent compiler will remove the test code. Although I don't think this is an excuse to poorly design/test your system.

无论您在什么环境下进行测试,都应尽可能接近真实世界.

Whatever environment you test in should be as close to real-world as possible.

像布莱恩一样的声音可能在他的回答中暗示了这个想法.与最后一个想法不同,这个想法尚未得到普遍认可,因此请带上一粒盐.

It sounds like Brian might be hinting at this idea within his answer. Unlike the last idea, this one isn't universally agreed upon, so take it with a grain of salt.

通过测试抽象,您可以提高对要测试的单元的尊重程度.您同意不会闲逛其内部并监视其内部状态.

By testing abstractions, you develop a level of respect for the unit being tested. You agree that you will not hoke around with its internals and spy on its internal state.

为什么在测试期间我不应该监视对象的状态?

Why shouldn't I spy on the state of objects during testing?

通过监视对象的内部,您正在引起以下问题:

By spying on the innards of an object, you are causing these problems:

  1. 您的测试将使您绑定到单元的特定实现.

例如...
是否想更改您的班级以使用其他排序算法?太糟糕了,您的测试将失败,因为您断言必须调用quicksort函数 .

For example...
Want to change your class to use a different sorting algorithm? Too bad, your tests will fail because you've asserted that the quicksort function must be called.

您将破坏封装.

通过测试对象的内部状态,您将很容易放松对象的某些隐私.这意味着您更多的 production 代码还将对您的对象具有更高的可见性.

By testing the internal state of an object, you will be tempted to loosen some of the privacy that the object has. This will mean that more of your production code will also have increased visibility into your object.

通过放松对象的封装,您诱使其他生产代码也依赖它.这不仅可以将您的 tests 绑定到特定的实现,而且还可以绑定整个系统本身.您希望这种情况发生.

By loosening the encapsulation of your object, you are tempting other production code to also depend on it. This can not only tie your tests to a specific implementation, but also your entire system itself. You do not want this to happen.

那我怎么知道这堂课呢?

Then how do I know if the class works?

测试所调用方法的前置条件和后置条件/结果.如果您需要更复杂的测试,请参阅我写的关于模拟和依赖项注入的最后一节.

Test the pre-conditions and post-conditions/results of the method being called. If you need more complex tests, look at the final section I've written on mocking and dependency injection.

只要您的生产代码与测试无关,我认为主要方法中有if (TEST_MODE)不一定很糟糕.

I don't think it's necessarily bad to have an if (TEST_MODE) in your main method as long as your production code remains independent of your tests.

例如:

public class Startup {

    private static final boolean TEST_MODE = false;

    public static void main(String[] args) {
        if (TEST_MODE) {
            TestSuite testSuite = new TestSuite();
            testSuite.execute();
        } else {
            Main main = new Main();
            main.execute();
        }
    }
}

但是,如果您的其他类知道他们正在测试模式下运行,则会成为一个问题.如果您在所有生产代码中都使用if (TEST_MODE),则表示您已经接受了我上面提到的问题.

However, it becomes a problem if your other classes know that they're running in test mode. If you have if (TEST_MODE) throughout all of your production code, you're opening yourself up to the problems I've mentioned above.

很明显,在Java中,您将使用诸如JUnit或TestNG之类的东西来代替它,但是我只是想分享对if (TEST_MODE)想法的看法.

Obviously in Java you would use something like JUnit or TestNG instead of this, but I just wanted to share my thoughts on the if (TEST_MODE) idea.

这是一个非常大的主题,所以我将答案的这一部分保持简短.

This is a very large topic, so I'll keep this section of the answer short.

  • 代替监视内部状态,使用模拟和依赖项注入.

使用模拟,您可以断言您已注入的模拟方法已被调用.更好的是,依赖项注入将使您的类对所注入内容的实现的依赖关系反转.这意味着您可以交换事物的不同实现,而不必担心.

With mocks, you can assert that a method of a mock you've injected has been called. Better yet, the dependency injection will invert your classes' dependency on the implementation of whatever you've injected. This means you can swap out different implementations of things without needing to worry.

这完全消除了在类中闲逛的需要.

This completely removes the need to hoke around inside your classes.

如果我强烈推荐阅读一本书,那就是 Jeff Langr 具有测试驱动开发的现代C ++编程.这可能是我用过的最好的TDD资源.

If there was one book I'd strongly recommend reading, it would be Modern C++ Programming with Test-Driven Development by Jeff Langr. It's probably the best TDD resource I've ever used.

尽管标题中有C ++,但它的主要焦点肯定是TDD.本书的开头讨论了这些示例应如何适用于所有(相似)语言.鲍勃叔叔甚至在前言中指出了这一点:

Despite having C++ in the title, its main focus is definitely TDD. The introduction of the book talks about how these examples should apply across all (similar) languages. Uncle Bob even states this in the foreword:

您需要成为C ++程序员才能理解吗?当然不会. C ++代码非常简洁,编写得井井有条,概念非常清晰,以至于任何Java,C#,C甚至Ruby程序员都不会遇到麻烦.

Do you need to be a C++ programmer to understand it? Of course you don't. The C++ code is so clean and is written so well and the concepts are so clear that any Java, C#, C, or even Ruby programmer will have no trouble at all.

这篇关于TDD:为什么让应用程序代码知道它正在测试而不是运行可能是错误的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆