背景
在 [Java] 如何自动生成简单的 PlantUML 类图 一文中,我分享了 ClassDiagramGenerator.java。将它编译之后,可以借助 ClassDiagramGenerator 生成简单的 PlantUML 类图。本文会借助它,生成 JUnit 4 框架中一些重要类的简要类图。
注意事项
本文所提到的类图,全都忽略了泛型信息,以及所有的字段和方法。
正文
TestClass
假设当前目录下已经有 JUnit 4 的 jar 包(我本地的 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 的插件,可以看到这样的效果 ⬇️
Runner
org.junit.runners.JUnit4
一个常用的 Runner 是 org.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 这个类时出了问题 ⬇️
在 org.junit.runners.ParentRunner 类中,用到了 org.junit.internal.AssumptionViolatedException,而后者实现了 org.hamcrest.SelfDescribing 接口 ⬇️
由于我们是直接用 -cp 选项的方式指定 junit-4.13.2.jar,所以在 classpath 里找不到 hamcrest 相关的类。
基于以上分析,我们可以把命令调整为 ⬇️ (需要先把 hamcrest 的 jar 包下载好并复制/移动到当前目录下)
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 的插件,可以看到这样的效果 ⬇️
org.junit.runners.Suite
另一个常用的 Runner 是 org.junit.runners.Suite。用如下的命令可以为它生成类图 ⬇️ (这里用到了 hamcrest 的 jar 包,理由请参考上文)
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 的插件,可以看到这样的效果 ⬇️
RunnerBuilder
下面列举了几个(我认为的)常见的 RunnerBuilder
org.junit.internal.builders.IgnoredBuilderorg.junit.internal.builders.JUnit4Builderorg.junit.internal.builders.AnnotatedBuilderorg.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 的插件,可以看到这样的效果 ⬇️
Statement
下面列举了几个(我认为的)常见的 Statement
org.junit.internal.runners.statements.InvokeMethodorg.junit.internal.runners.statements.RunBeforesorg.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 的插件,可以看到这样的效果 ⬇️