简体   繁体   English

在测试时使用反射破坏封装是多么邪恶?

[英]How evil is it to use reflection to break encapsulation when testing?

I'm testing 3 new classes that make 3 collections of objects that are serialized to a database. 我正在测试3个新类,这些类生成3个序列化为数据库的对象集合。 1 of the classes has a hard coded array of strings. 其中一个类具有硬编码的字符串数组。 The 3 collections end up the same size as the array of strings and each object in the collection gets a name/tag based on string in the array. 3个集合的结尾大小与字符串数组相同,集合中的每个对象都根据数组中的字符串获取名称/标记。

One of my tests is an end-to-end test that will try to make all three collections. 我的一个测试是端到端测试,它将尝试制作所有三个集合。 I would like to have access to the array of strings for testing but it's private. 我想访问用于测试的字符串数组,但它是私有的。 I see three possible ways to deal with this: 我看到三种可能的方法来解决这个问题:

  • Make it protected <- Office policy is to NOT modify code design for the sake of testing. 使其受到保护< - Office策略是不为了测试而修改代码设计。
  • Copy array to test class <- Now array changes must be maintained in two locations. 将数组复制到测试类< - 现在必须在两个位置维护数组更改。 Ow. 噢。
  • Use reflection to peek at privates <- This works but is it more or less evil than the alternatives? 使用反思来窥视私人< - 这有效,但它或多或少比其他选择更邪恶?

Can you think of a fourth way? 你能想到第四种方式吗? Is there a good reason to not use reflection for this? 是否有充分理由不使用反射?

It really depends on what your test is trying to exercise. 这实际上取决于你的测试试图运用什么。 In general, if you are testing the internal implementation details of your code, you are probably doing the wrong thing with your tests. 通常,如果您正在测试代码的内部实现细节,那么您可能在测试时做错了。 After all, your tests should be exercising the observable effects of your code, not the implementation details. 毕竟,您的测试应该是执行代码的可观察效果 ,而不是实现细节。 Tests that exercise implementation details are brittle (needing to be updated whenever the implementation changes) and usually are just a copy of the implementation. 执行实现细节的测试很脆弱(需要在实现更改时进行更新),并且通常只是实现的副本。 Also, because they mirror the implementation, bugs in the implementation are likely to be reflected in the tests, as well, so such tests are typically of dubious value. 此外,因为它们反映了实现,所以实现中的错误也可能反映在测试中,因此这些测试通常具有可疑的价值。

A better approach for such a thing is to use an interface to represent your database object and to use a mocking framework such as mockito to verify that the data you expect is written to and read from the database, without inspecting the innards of how your code is storing the data internally before writing it to the database. 更好的方法是使用一个接口来表示您的数据库对象,并使用模拟框架(如mockito)来验证您期望的数据是否写入数据库并从数据库中读取,而不检查代码的内部结构在将数据写入数据库之前将数据存储在内部。

Also, in terms of not writing code differently for tests... in general, it is good practice not to have test-only methods in your production code. 此外,就不为测试编写不同的代码而言......通常,最好不要在生产代码中使用仅测试方法。 However, refactoring code to make it more modular (and therefore more testable), is a generally good coding practice to have. 但是,重构代码使其更加模块化(因此更易于测试),这是一种通常很好的编码实践。

The variable itself should stay private, but you can add a getter with default (package-private) access. 变量本身应保持私有,但您可以添加具有默认(包私有)访问权限的getter。

If the test code is located in the same package. 如果测试代码位于同一个包中。 this solves the problem right away. 这马上解决了这个问题。

If the test code from other packages needs to access this getter, you will have to write some boilerplate of the following form: 如果其他软件包的测试代码需要访问此getter,则必须编写以下格式的样板:

The class under test has private field and a getter with default access: 被测试的类具有私有字段和具有默认访问权限的getter:

public class MyClass {

    private Object someData;

    // you should research the usage of these or similar annotations
    // they will help your IDE to catch improper usage of test-only methods
    //@com.google.common.annotations.VisibleForTesting
    //@org.jetbrains.annotations.TestOnly
    Object getSomeData() {
        return someData;
    }

}

The test code contains a helper that exposes getter as public so it can be used from tests in other packages: 测试代码包含一个帮助器,它将getter公开为public,因此可以从其他包中的测试中使用它:

public class MyClassTestHelper {

    public static Object getSomeData(MyClass instance) {
        return instance.getSomeData();
    }

}

You should also look at How do I test a class that has private methods, fields or inner classes? 您还应该看看如何测试具有私有方法,字段或内部类的类? (your question can be even considered duplicate of it) and annotation to make a private method public only for test classes . (您的问题甚至可以被认为是重复的)和注释,以使私有方法仅对测试类公开

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

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