简体   繁体   English

如何测试只修改私有类成员变量的void方法?

[英]How to test void method that only modifies private class member variables?

I'm trying to unit test a method in a class that initializes some private fields: 我正在尝试在一个初始化一些私有字段的类中对一个方法进行单元测试:

public void init(Properties props) throws Exception {

    this.language = props.getProperty(Constants.LANGUAGE,Constants.LANGUAGE_DEFAULT);   
    this.country = props.getProperty(Constants.COUNTRY,Constants.COUNTRY_DEFAULT);

        try {
            this.credits = Integer.valueOf(props.getProperty(Constants.CREDITS_OPTION_NAME, Constants.CREDITS_DEFAULT_VALUE));
        } catch (NumberFormatException e) {
            throw new Exception("Invalid configuration: 'credits' does not contain a valid integer value.", e);
        }
        //rest of method removed for sake of simplicity
    }

My dilemma is that I want to assert that the language, country and credits fields have been set after calling init, however they are private with no public accessor methods. 我的困境是我想断言语言,国家和信用字段是在调用init之后设置的,但它们是私有的,没有公共访问器方法。 I see there are two solutions for testing this: 我看到有两种解决方案可用于测试:

  1. Make public methods for accessing the private fields, then call these methods after testing the init method. 制作访问私有字段的公共方法,然后在测试init方法后调用这些方法。
  2. Make the unit test just call init method, and assume everything worked correctly is no exception was thrown. 使单元测试只调用init方法,并假设一切正常工作都没有抛出异常。

What do you think is the ideal way to test this method? 您认为测试此方法的理想方法是什么?

You can use reflection to get the values of private fields. 您可以使用反射来获取私有字段的值。 For example: 例如:

Field field = YourClass.class.getDeclaredField("language");
field.setAccessible(true); //override the access restriction of it being private
field.get(yourObject);

If there's spring on your classpath, you can use its ReflectionUtils / ReflectionTestUtils . 如果类路径上有弹簧,则可以使用其ReflectionUtils / ReflectionTestUtils

It is sometimes argued that private fields should not be verified, and only the public state of the object is the point of unit-testing. 有时人们认为不应该验证私有字段,只有对象的公共状态才是单元测试的重点。 From that perspective it may be better to expose a getter, or even better - thrown an exception. 从这个角度来看,暴露一个getter可能更好,甚至更好 - 抛出一个异常。

If the object is in invalid state if the fields are not set, then it should be the responsibility of the object itself to enforce its validity, by throwing an exception. 如果对象处于无效状态(如果未设置字段),则对象本身应负责通过抛出异常来强制其有效性。

I want to assert that the language, country and credits fields have been set after calling init 我想声明在调用init之后已经设置了语言,国家和信用字段

Some philosophy: why do you care whether they are set correctly? 一些哲学:你为什么关心它们是否设置正确? If the answer is "so the class then behaves correctly", then you can test that they have been set correctlty by testing that expected subsequent behaviour. 如果答案是“所以该类的行为正确”,那么您可以通过测试预期的后续行为来测试它们是否已经设置正确。 If however setting them incorrectly has no effect they are redundant and you should remove them. 但是,如果设置不正确无效,则它们是多余的,您应该删除它们。

Another poster has suggested using reflection to access the private fields. 另一张海报建议使用反射来访问私人领域。 I advise against this; 我建议不要这样做; anything marked private should be an implementation detail of the class, and therefore should not be directly tested. 标记为private的任何内容都应该是该类的实现细节,因此不应直接测试。 You should instead test the published API of your class. 您应该测试您的类的已发布API。 You then have the freedom to refactor it easilly by changing implementation (private) details. 然后,您可以通过更改实现(私有)详细信息,轻松地自由地重构它。

I usually try to avoid tests that depend on the internal structure of the class under test. 我通常会尝试避免依赖于被测试类的内部结构的测试。 I'd much rather test this by testing some method that then uses these fields. 我宁愿通过测试一些然后使用这些字段的方法来测试它。

If you're doing strict TDD, you shouldn't even add those fields until you have a test case that actually takes advantage of them :) 如果你正在进行严格的TDD,你甚至不应该添加这些字段,直到你有一个实际利用它们的测试用例:)

Does your JUnit call the method directly? 您的JUnit是否直接调用该方法? Then the reference to the Property Object is the same, you should be able to access Language and Country, for credits do the recalculation in your JUnit. 然后对属性对象的引用是相同的,您应该能够访问语言和国家,以便在JUnit中重新计算。

Public accessor for private methods is also a good choice. 私人方法的公共访问者也是一个不错的选择。

Personally I would just check the public methods. 我个人会检查公共方法。 Sometimes you need to check the internals, but this is rare. 有时您需要检查内部,但这种情况很少见。

BTW: An alternative to public getters is to make the unit test in the same package and provide package local getters. BTW:公共getter的替代方案是在同一个包中进行单元测试并提供包本地getter。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM