浅解 JUnit 4 第二十篇:自动生成简单的 PlantUML 类图

41 阅读2分钟

背景

[Java] 如何自动生成简单的 PlantUML 类图 一文中,我分享了 ClassDiagramGenerator.java。将它编译之后,可以借助 ClassDiagramGenerator 生成简单的 PlantUML 类图。本文会借助它,生成 JUnit 4 框架中一些重要类的简要类图。

注意事项

本文所提到的类图,全都忽略了泛型信息,以及所有的字段和方法。

正文

TestClass

假设当前目录下已经有 JUnit 4jar 包(我本地的 jar 包名称为 junit-4.13.2.jar)。那么我们就可以通过如下的命令来生成 org.junit.runners.model.TestClass 的类图。

java -cp .:junit-4.13.2.jar ClassDiagramGenerator 'org.junit.runner.Runner'

运行结果如下 ⬇️

@startuml

interface org.junit.runner.Describable
abstract org.junit.runner.Runner
org.junit.runner.Describable <|.. org.junit.runner.Runner

@enduml

借助 Intellij IDEA (Community Edition)PlantUML 的插件,可以看到这样的效果 ⬇️

image.png

Runner

org.junit.runners.JUnit4

一个常用的 Runnerorg.junit.runners.JUnit4。我们先看看它的类图。先用如下的命令尝试为它生成类图 ⬇️

java -cp .:junit-4.13.2.jar ClassDiagramGenerator 'org.junit.runners.JUnit4'

但会看到如下的报错

Exception in thread "main" java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:962)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:144)
	at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:776)
	at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:691)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:620)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:578)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:467)
	at java.base/java.lang.Class.forName(Class.java:458)
	at ClassDiagramGenerator.convert(ClassDiagramGenerator.java:67)
	at ClassDiagramGenerator.main(ClassDiagramGenerator.java:21)
Caused by: java.lang.ClassNotFoundException: org.hamcrest.SelfDescribing
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
	... 13 more

我们可以把命令调整为这样 ⬇️ 看看都加载了哪些类

java -cp .:junit-4.13.2.jar -verbose:class ClassDiagramGenerator 'org.junit.runners.JUnit4'

完整的输出有几百行,这里就不粘贴了。经过一番分析和对比,我怀疑是在加载 org.junit.runners.ParentRunner 这个类时出了问题 ⬇️

image.png

org.junit.runners.ParentRunner 类中,用到了 org.junit.internal.AssumptionViolatedException,而后者实现了 org.hamcrest.SelfDescribing 接口 ⬇️

image.png

由于我们是直接用 -cp 选项的方式指定 junit-4.13.2.jar,所以在 classpath 里找不到 hamcrest 相关的类。

基于以上分析,我们可以把命令调整为 ⬇️ (需要先把 hamcrestjar 包下载好并复制/移动到当前目录下)

java -cp .:junit-4.13.2.jar:hamcrest-core-1.3.jar ClassDiagramGenerator 'org.junit.runners.JUnit4'

这次总算能成功运行了,运行结果如下 ⬇️

@startuml

interface org.junit.runner.manipulation.Sortable
interface org.junit.runner.manipulation.Orderable
interface org.junit.runner.Describable
interface org.junit.runner.manipulation.Filterable
abstract org.junit.runners.ParentRunner
abstract org.junit.runner.Runner
class org.junit.runners.BlockJUnit4ClassRunner
class org.junit.runners.JUnit4
org.junit.runner.Describable <|.. org.junit.runner.Runner
org.junit.runner.manipulation.Sortable <|-- org.junit.runner.manipulation.Orderable
org.junit.runner.Runner <|-- org.junit.runners.ParentRunner
org.junit.runner.manipulation.Filterable <|.. org.junit.runners.ParentRunner
org.junit.runner.manipulation.Orderable <|.. org.junit.runners.ParentRunner
org.junit.runners.ParentRunner <|-- org.junit.runners.BlockJUnit4ClassRunner
org.junit.runners.BlockJUnit4ClassRunner <|-- org.junit.runners.JUnit4

@enduml

借助 Intellij IDEA (Community Edition)PlantUML 的插件,可以看到这样的效果 ⬇️

image.png

org.junit.runners.Suite

另一个常用的 Runnerorg.junit.runners.Suite。用如下的命令可以为它生成类图 ⬇️ (这里用到了 hamcrestjar 包,理由请参考上文)

java -cp .:junit-4.13.2.jar:hamcrest-core-1.3.jar ClassDiagramGenerator 'org.junit.runners.Suite'

运行结果如下

@startuml

interface org.junit.runner.Describable
interface org.junit.runner.manipulation.Sortable
interface org.junit.runner.manipulation.Filterable
interface org.junit.runner.manipulation.Orderable
abstract org.junit.runners.ParentRunner
abstract org.junit.runner.Runner
class org.junit.runners.Suite
org.junit.runner.Describable <|.. org.junit.runner.Runner
org.junit.runner.manipulation.Sortable <|-- org.junit.runner.manipulation.Orderable
org.junit.runner.Runner <|-- org.junit.runners.ParentRunner
org.junit.runner.manipulation.Filterable <|.. org.junit.runners.ParentRunner
org.junit.runner.manipulation.Orderable <|.. org.junit.runners.ParentRunner
org.junit.runners.ParentRunner <|-- org.junit.runners.Suite

@enduml

借助 Intellij IDEA (Community Edition)PlantUML 的插件,可以看到这样的效果 ⬇️

image.png

RunnerBuilder

下面列举了几个(我认为的)常见的 RunnerBuilder

  • org.junit.internal.builders.IgnoredBuilder
  • org.junit.internal.builders.JUnit4Builder
  • org.junit.internal.builders.AnnotatedBuilder
  • org.junit.internal.builders.AllDefaultPossibilitiesBuilder

用如下的命令可以为它们生成类图 ⬇️

java -cp .:junit-4.13.2.jar ClassDiagramGenerator 'org.junit.internal.builders.IgnoredBuilder' 'org.junit.internal.builders.JUnit4Builder' 'org.junit.internal.builders.AnnotatedBuilder' 'org.junit.internal.builders.AllDefaultPossibilitiesBuilder'

运行结果如下

@startuml

abstract org.junit.runners.model.RunnerBuilder
class org.junit.internal.builders.IgnoredBuilder
class org.junit.internal.builders.JUnit4Builder
class org.junit.internal.builders.AnnotatedBuilder
class org.junit.internal.builders.AllDefaultPossibilitiesBuilder
org.junit.runners.model.RunnerBuilder <|-- org.junit.internal.builders.IgnoredBuilder
org.junit.runners.model.RunnerBuilder <|-- org.junit.internal.builders.JUnit4Builder
org.junit.runners.model.RunnerBuilder <|-- org.junit.internal.builders.AnnotatedBuilder
org.junit.runners.model.RunnerBuilder <|-- org.junit.internal.builders.AllDefaultPossibilitiesBuilder

@enduml

借助 Intellij IDEA (Community Edition)PlantUML 的插件,可以看到这样的效果 ⬇️

image.png

Statement

下面列举了几个(我认为的)常见的 Statement

  • org.junit.internal.runners.statements.InvokeMethod
  • org.junit.internal.runners.statements.RunBefores
  • org.junit.internal.runners.statements.RunAfters

用如下的命令可以为它们生成类图 ⬇️

java -cp .:junit-4.13.2.jar ClassDiagramGenerator 'org.junit.internal.runners.statements.InvokeMethod' 'org.junit.internal.runners.statements.RunBefores' 'org.junit.internal.runners.statements.RunAfters'

运行结果如下

@startuml

abstract org.junit.runners.model.Statement
class org.junit.internal.runners.statements.InvokeMethod
class org.junit.internal.runners.statements.RunBefores
class org.junit.internal.runners.statements.RunAfters
org.junit.runners.model.Statement <|-- org.junit.internal.runners.statements.InvokeMethod
org.junit.runners.model.Statement <|-- org.junit.internal.runners.statements.RunBefores
org.junit.runners.model.Statement <|-- org.junit.internal.runners.statements.RunAfters

@enduml

借助 Intellij IDEA (Community Edition)PlantUML 的插件,可以看到这样的效果 ⬇️

image.png

参考资料