单元测试、静态和工厂

发布于 2024-11-01 03:46:56 字数 655 浏览 1 评论 0原文

我正在用 Java 实现一个模型,它需要迭代一个集合并经历多个识别阶段,它涉及 for 循环、while 循环等。这是我想要在细粒度级别测试的东西,以便我有信心它已得到正确实施。

我用它作为开始单元测试的机会,因为我认为这对我的代码有益。从那时起,我一直在阅读大量书籍来快速了解 JUnit 和单元测试。

基本上,我的问题归结为我收到的两条相互矛盾的建议:

1)静态是邪恶的。不要接触静电。也不要测试私有,你可能想要一个类。
2) 使用工厂进行创建,以允许使用参数进行依赖项注入 - 可能允许使用模拟和存根进行隔离。

在我的示例中,我希望执行以下操作:

double height = 223.42; // this was set iterating over a collection of doubles
//blah
HeightBounds b = HeightBounds.getHeightBounds(height);
//more blah

我这样做是为了避免构建非常长且复杂的代码块,我只能对其进行整体测试。这样我就有了可以测试的公共可访问对象,以确保系统组件全部正确运行。

常识告诉我,静态工厂没有任何问题,而且它们很容易测试,但是考虑到我正在学习测试驱动设计,我是否错过了一些非常明显的东西?

谢谢

I am implementing a model in Java which requires iterating over a collection and going through a number of identification stages, it involves for loops, while loops etc. It is the sort of thing I want to test at a fine-grained level so that I have confidence it has been implemented properly.

I have used it as an opportunity to start unit testing, as it is something I recognise as being beneficial to my code. I have since been reading a forest of books to get up to speed with JUnit and unit testing.

Basically my question comes down to two conflicting pieces of advice I have received:

1) Statics are evil. Do not touch statics. Do not test privates either, you probably want a class there instead.
2) Use factories for creation to allow dependency injection using parameters - potentially allowing use of mocks and stubs for isolation.

In my example I am looking to perform an operation along the lines of:

double height = 223.42; // this was set iterating over a collection of doubles
//blah
HeightBounds b = HeightBounds.getHeightBounds(height);
//more blah

I have done this in order to avoid building up what would become a very long and complicated block of code, which I can only test in its entirety. This way I have public accessible objects that I can test to ensure the system components all perform correctly.

Common sense says to me there is nothing wrong with static factories, and that they are easily tested, but am I missing something blindingly obvious given I am learning test-driven design?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

屌丝范 2024-11-08 03:46:56

静态工厂类引入了您的类和 HeightBounds 类之间的耦合。这可能会使您的类难以测试,例如,如果 HeightBounds 关闭并在数据库中查找信息,或者从 Web 服务等读取。

如果您注入了 IHeightBounds > 实现到你的类中,然后你可以模拟它,这样你就可以测试当你的类的依赖项执行某些操作时会发生什么。

例如,如果 HeightBounds 抛出异常怎么办?或者返回null?或者您想测试何时返回特定的 HeightBound ?使用接口很容易模拟这种行为,而使用静态工厂则更困难,因为您已经制造了数据以在类中创建所需的结果。

您仍然可以只有一个 HeightBounds 实现,并且能够单独测试它,但是您甚至可以在没有实际实现的情况下测试上面的方法。

我可能会有一个 IHeightBoundFactory 接口并将实现注入到该类中。

至于测试私有,通常你不想这样做。您想要测试两件事之一,要么结果是您预期的,要么交互是您预期的。

如果您有一个名为 Add 的方法和一个名为 GetAll 的方法,那么您可能需要在调用 Add 然后调用 时进行测试GetAll 您将取回您添加的那个。你并不关心它是如何实现的,只关心它是否有效。这是测试结果。通常在这种情况下,您需要创建返回数据的模拟对象。这似乎就是你的情况。

如果当您调用 Add 时,您希望记录所添加的内容,那么您想要测试与日志记录依赖项的交互,因此您注入一个模拟依赖项并验证与该类的交互是否发生在您调用了Add。通常,在这种情况下,您希望创建设置了期望的模拟对象,并验证是否已满足这些期望。在您上面描述的情况下,这似乎没有必要。

The static factory class introduces coupling between your class and the HeightBounds class. this might make your class difficult to test, if for example HeightBounds goes off and looks in DB for information, or reads from a web service etc etc.

If you instead injected an IHeightBounds implementation into your class then you could mock that out so you could test what happens when the dependencies of you class do certain things.

For example what if HeightBounds throws an exception? or returns null? Or you want to test when a particular HeightBound is returned? With an interface it is easy to mock this behaviour, with a static factory it is more difficult as you have manufacture the data to create the desired results in the class.

You could still only have a single implementation of HeightBounds and would be able to test that in isolation, but you would be able to test your method above without even having an real implementation.

I would probably have an IHeightBoundFactory interface and inject an implementation into the class.

As for testing the privates, generally you don't want to. You want to be testing one of 2 things, either that the results are what you expected or that the interactions are what you expected.

If you have a method called Add and a method called GetAll then you might want to test that when you call Add and then call GetAll you get back the one you added. you don't care how this is implemented, just that it works. this is testing the results. Generally in this situation you want to create mock objects that return data. This seems to be your situation.

If when you call Add you expect that what is being added is logged, then you want to test the interactions with the logging dependency, so you inject a mock dependency and verify that the interaction with that class happened when you called Add. Generally in this situation you want to create mock objects that have expectations set, and you verify that those expectations have been met. It doesn't look this is necessary in the situation you described above.

秋意浓 2024-11-08 03:46:56

静态是邪恶的。不要接触静电。

这里的“静态”可能意味着单例,即全局状态。这确实很难在单元测试中使用,并且可能会引入很多微妙的问题,所以一般情况下最好避免它。然而,静态成员(字段、方法或内部类)通常本身不一定是问题。

也不要测试私有,你可能想要一个类。

一般来说,如果您觉得需要测试私有方法,则表明您的 API 粒度不够细,并且封闭类可能试图做太多事情。通常,您可能会识别出一些连贯的功能组,最好将其提取到单独的类中。这改进了您的设计并且反过来又使单元测试变得更加容易。

Statics are evil. Do not touch statics.

"static" here probably means Singletons, i.e. global state. That is indeed difficult to use in unit tests, and can introduce lots of subtle issues, so it is better to avoid it in general. However, static members (fields, methods or inner classes) in general are not necessarily a problem per se.

Do not test privates either, you probably want a class there instead.

This is true in general, if you feel the need to test a private method, it is a sign that your API is not fine grained enough, and the enclosing class may be trying to do too much. Often you may identify some coherent group of functionality which is better to extract into a separate class. This improves your design and in turn makes unit testing easier.

扮仙女 2024-11-08 03:46:56

静态工厂的一个问题是,您无法通过模拟替换工厂(有时还替换工厂创建的对象)。 - 这就是 IOC 容器如此有用的原因之一。

A problem with static factories is, that you are not able to replace the factories (and sometime the objects created by the factories) by mocks. - That is one reason why IOC Containers are so usefull.

冧九 2024-11-08 03:46:56

静态方法基本上杀死了单元测试。

当您想要对应用程序进行单元测试时,基本思想之一是能够隔离代码的不同部分。您通常通过为您的环境连接模拟对象来完成此操作。如果您使用静态方法,则无法连接任何内容。此外,使用静态方法隐藏了对象之间的依赖关系。

在最后一段中,您说您想学习测试驱动设计。如果您在编写代码之后编写测试,那么您的测试实际上并没有驱动任何东西。首先编写你的测试。

关于私有方法,您通常会对使用这些私有方法的公共方法进行完整的测试覆盖,因此无论如何您都会覆盖它们。如果您有一个非常复杂的私有方法想要测试(您不应该),只需使用反射来使其可访问。我宁愿破坏封装也不愿使用未经测试的代码。

Misko Hevery 有一篇非常不错的帖子 关于这个话题。

Static methods basically kill unit testing.

One of the basic ideas when you want to unit test your application is the ability to isolate different portions of your code. You usually do this by wiring mock objects for your environment. You can't wire anything if you are using static methods. Moreover, using static methods hides dependencies between objects.

In your last paragraph you say you want to learn test-driven design. If you are writing your tests after you've written your code your tests are not actually driving anything. Write your tests first.

Regarding private methods, you would usually have full test coverage of the public methods that use those private methods, so you are going to cover them anyway. If you have a really complex private method that you want to test (you should not) just use reflection to make it accessible. I'd rather break encapsulation than having untested code.

Misko Hevery has a very nice post on this topic.

只是在用心讲痛 2024-11-08 03:46:56

静态方法本身并不邪恶。查看 JDK 有多少个。静态方法也需要进行单元测试,因此如果有的话请继续测试它们。

所以说静态方法会杀死单元测试是不正确的。

但是,如果您只是为了在单元测试中编写更少的代码而进行静态分析,那么这是一条错误的道路,因为正如其他人所说,您应该更好地使用常用的 API 来使用对象 - 因为这就是您想要测试的内容。

以及首先编写测试的完整 ACK - 它还将帮助您设计更好的 API,正确地削减您的课程。

Static methods are not evil per se. Look in JDK how many of them are there. Static methods also need to be unit tested, so if you have any go on and test them.

So it's not true that static methods kill unit testing.

But if you make statics only to write less code in unit tests then it is a wrong path since as others have stated you should better use your objects using your usual API - since this is what you want to test.

And full ACK for writing tests first - it will also help you design better API, cut you classes right.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文