当前位置: 首页 > 知识库问答 >
问题:

Java-访问私有类

晋天逸
2023-03-14

我知道如何访问私有变量,但我正在尝试测试以下类:

ProcessStatusResult:

@Getter
class ProcessStatusBody {
  public ProcessStatusBody(ProcessStatus status) {
    this.status = status;
  }
  ProcessStatus status;
}

@Getter
public class ProcessStatusResult {
  ProcessStatusBody body;
  ...
  
  public ProcessStatusResult(ProcessStatus status) {
    body = new ProcessStatusBody(status);
    ...
  }
}

在我的测试中,我需要在ProcessStatusBody中获取ProcessStatus来验证它,但我不知道如何做到这一点。

有没有一种方法可以使用反射(或其他方法)来访问它,而不必仅仅为了测试而在ProcessStatusResult中添加getter?

共有2个答案

郭弘方
2023-03-14

这里有一些使用反射的工作代码:

// Assuming you have the objects
ProcessStatusResult processStatusResult = new ProcessStatusResult(new ProcessStatus());
ProcessStatusBody processStatusBody = processStatusResult.getBody();

try {
    // The status field, you know the name, right?
    Field privateField = ProcessStatusBody.class.getDeclaredField("status");

    // Set the accessibility to true since it is not visible
    privateField.setAccessible(true);

    // Here we go
    ProcessStatus status = (ProcessStatus) privateField.get(processStatusBody);
    
    System.out.println(status);
    
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
    // do something
}

对不起,我不知道你说:“有没有办法使用反射......”

顾淳
2023-03-14

从广义上讲,有三种不同的方法来解决这个问题。

将(Unit1)测试与其测试的代码放在同一个包中是很常见的。不同的“源代码根”,相同的包。你会有:

src/main/java/com/foo/Whatever.java
src/test/java/com/foo/TestWhatever.java

当你这么做的时候,你的测试代码可以“看到”所有包私有的东西(因为,同一个包)。

一些项目希望强调这一点,并有一个注释,表明“为了测试代码,这个项目是包私有的;如果你真的想全力以赴,你可以添加linter工具,检测与同一个包(不是测试代码)中其他源文件中标记的实体进行交互的任何尝试,并将其标记为错误。

不幸的是,根据我的经验,这些工具并不常用,我也不知道有哪种linter工具能做到这一点。一个比较常见的注释是番石榴的@VisibleForTesting。除了用作文档之外,它什么都不做(目前,人们可以编写一个linter工具来实际检查样式冲突)。

测试框架可以做到这一点,但它严重阻碍了生产率。如果要访问状态变量,只需键入body即可并在IDE中按CTRL空格键或等效键,它将显示在那里,您只需选择它,您可以在键入后单击CMD或自动完成它,直接进入其定义,如果您键入名称,IDE将在它下面加上红色波浪线。

更换车身。状态,类似于反映。getField(body,“status”,ProcessStatus.class) 这真是一团糟。它很长,很难看,泛型与类型不匹配(如果status属于List类型怎么办

因此,这也不是很好,因此不经常使用。

私有的也许只是私有的意思。它并不意味着被任何“源代码外部”文件所使用,包括单元测试。没有一个源文件完全由100%的私有的一切组成——有一些你应该从“外部”插入的应用编程接口,测试代码可以获得除了私有的之外的所有东西(所以,包私有的、受保护的公共的都可以被测试代码访问)。测试公共应用编程接口部分,不要测试私有的东西——毕竟,私有背后的正常想法是,你可以随心所欲地处理这些东西,改变它们的工作,改变它们的签名,你需要检查的只是仅仅基于你正在查看的源文件中的其他内容产生了什么影响。

不必将其扩展到:“...哦,你还需要重新访问与此直接交互的所有单元测试”。

制作一个真正的公共类应用编程接口(如果你愿意,包是私有的,但是你写它的实际意图是这个源文件之外的代码会想要使用这个特性)并测试它。或者,如果这个字段真的不是同一个包中的其他源文件都应该知道的细节,那么就不要测试它——它是一个粒度太细的测试。

在如此细粒度的水平上进行测试有好有坏。一般来说,这种细粒度水平会使测试更简单、更“局部化”(测试发现的任何错误都将指向实际问题),但深入测试意味着你需要大量的测试,大多数测试都变得琐碎,这给重构带来了巨大的阻力——毕竟,即使是简单的重构也需要修改大量的测试。你还面临着“复制综合症”的风险,即同一个程序员编写测试单元和代码,因此任何精神错误都可能存在于两者中,从而使测试完全无用。

模仿综合症的一个解决方案是将测试的编写和代码的编写分开。当一个人编写测试,另一个人编写实现时,这显然很容易做到,但是你可以自己做——只要确保在编写测试和编写实现之间有时间和“精神Rest”,足以防止你的大脑在编写测试和实现时重播完全相同的推理(这可能是连续两次犯同样的错误而没有意识到的途径)。

然而,当你像这样解开谜团时,用“测试私有内容”的粒度进行测试会变得非常奇怪和笨拙——像这样的测试往往遵循“有一些API规范,这就是我们测试的”,而私有内容根据定义不属于这样的规范。

不管你是想先写测试,还是最后写测试,同样的原则也适用。编写测试是很奇怪的,而且在编写测试的过程中,已经开始编写实现它所需的私有方法:这不是你作为测试编写者的“工作”。

编写测试实现选择的测试也同样奇怪(也许稍微不那么奇怪)。

SO不是用于发表意见的,所以我不会在上面花超过两句话,但是我强烈的建议是第三种选择。私有的意思是:不直接测试。

1)实际上,任何测试,如果它测试的范围明显局限于某个“单元”的代码,而在项目的代码样式规则中,这些“单元”的代码需要放在一个包中。这两个概念(“我在包中塞了什么”和“这个测试是什么”至少需要排列成一行,或者“我测试什么”需要比这更细粒度)。换句话说,测试整个项目的集成测试根本不能使用这种策略,但是如果这些测试是测试私有变量,我很确定你做错了什么。

 类似资料:
  • 问题内容: 是在类级别还是在对象级别的私有成员访问权限。如果是在对象级别,则以下代码不应编译 请说明在sub的messWithI()方法中访问obj的成员i是否有效 问题答案: 正如DevSolar所说的,它处于(顶级)类级别。 从Java语言规范的6.6节开始: 否则,如果将成员或构造函数声明为私有,则仅当访问发生在包含成员或构造函数的声明的顶级类(第7.6节)的主体内时,才允许访问。 请注意,

  • 问题内容: 众所周知,私有字段不会在类之间继承。令我着迷的是它如何用于内部静态类。考虑以下代码: 您能否解释一下如何访问其他内部类的私有字段?如果合法,为什么只能通过“ super.XXX”构造实现? 问题答案: 内部类是Java的较晚入门。添加它们时,它们仅作为编译器扩展添加,对JVM不变。 语言规范指出,内部类被允许访问在其内声明的类的私有成员。包括其他内部类。 为了使其工作,编译器会生成桥接

  • 问题内容: 我希望我说的是我的话。我有这样的课: 和其他这样的类: 这是从其他类(在该示例代码中)访问和更改其值的正确方法吗,是否有更好或更合适的解决方案?请注意,这是具有方法的类。 问题答案: 从另一个类访问私有变量的正确方法是使用getter和setter方法。否则,您应该将该变量公开。 那是: 但是,直接返回私有数据是一种不好的做法- 允许外部代码修改您的私有状态。通常,您应该返回私有数据的

  • 我正在将文件从php上传到s3bucket.its上传成功,但当我检索图像时,我得到以下错误 如果我在上传文件时设置为公开,那么我可以检索它,但我想防止未经授权的用户。 上载文件代码 在问问题之前,我已经参考了许多网站,但它对我没有帮助 Amazon S3查看私人文件 PHP Amazon S3通过URL访问私人文件 如何通过Zend_Service_Amazon_S3访问Amazon s3私有桶

  • 为什么我能够直接访问的私有属性在的方法的实现中?似乎使用getter应该是访问它的唯一(如果不是,最好的实践)方式。我错过了什么?

  • 我正在尝试将一个图像推送到我的docker私有存储库: Docker告诉我: push引用存储库[living-registry.com:5000/busybox]Get https://living-registry.com:5000/v1/_ping:read tcp 195.83.122.16:39714->195.83.122.16:5000:read:对等体重置连接 这些命令正在Core