单元测试-junit

不念不忘少年蓝@ 2022-11-12 10:00 413阅读 0赞

脱离开发工具使用junit运行一个测试类

本文以最基础的BlockJUnit4ClassRunner junit内置对象介绍

实例化一个被测试对象 并且被测试类必须具备无参数构造方法 并且只能有一个无参数构造方法

  1. import org.junit.runner.JUnitCore;
  2. import org.junit.runners.BlockJUnit4ClassRunner;
  3. import org.junit.runners.model.InitializationError;
  4. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  5. public class JunitExample {
  6. public static void main(String[] args) throws InitializationError {
  7. JUnitCore core = new JUnitCore();
  8. // core.run(new SpringJUnit4ClassRunner(CheckServiceTest.class));
  9. core.run(new BlockJUnit4ClassRunner(CheckServiceTest.class));
  10. }
  11. }

组件介绍

org.junit.runner.JUnitCore#run(org.junit.runner.Runner)

org.junit.runners.BlockJUnit4ClassRunner
junit默认的基础执行器

org.junit.runner.notification.RunNotifier

  1. private final List<RunListener> listeners = new CopyOnWriteArrayList<RunListener>();
  2. private volatile boolean pleaseStop = false;

管理监听列表和终止信号

org.junit.runner.Runner

  1. public abstract Description getDescription();
  2. public abstract void run(RunNotifier notifier);
  3. public int testCount() {
  4. return getDescription().testCount();
  5. }

定义执行扩展点 和 测试描述信息管理

org.junit.runner.Description

  1. private final Collection<Description> fChildren = new ConcurrentLinkedQueue<Description>();
  2. private final String fDisplayName;
  3. private final Serializable fUniqueId;
  4. private final Annotation[] fAnnotations;
  5. private volatile /* write-once */ Class<?> fTestClass;

测试类相关信息的载体

org.junit.runner.Result.Listener
org.junit.runner.notification.RunListener

org.junit.runners.model.Statement

  1. public abstract void evaluate() throws Throwable;

就一个抽象方法 提供了实际执行器的扩展点

org.junit.runners.model.RunnerScheduler
单测任务调度管理

几段代码

runner.run(notifier);
内部实例化执行单元org.junit.runners.model.Statement的实现类 ,以evaluate方法实现实际任务提交的动作等其他的实现逻辑,以返回的实例化对象的evaluate显示调用来触发实际的后续job提交和执行逻辑

  1. org.junit.runner.JUnitCore#run(org.junit.runner.Runner)
  2. public Result run(Runner runner) {
  3. Result result = new Result();
  4. RunListener listener = result.createListener(); 钩子函数
  5. notifier.addFirstListener(listener);
  6. try {
  7. notifier.fireTestRunStarted(runner.getDescription()); 声明测试执行开始 实例化org.junit.runner.notification.RunNotifier.SafeNotifier 触发钩子函数的钩子testRunStarted run
  8. runner.run(notifier); 执行器的run 实际单元测试执行逻辑
  9. notifier.fireTestRunFinished(result); 声明测试执行完成
  10. } finally {
  11. removeListener(listener);
  12. }
  13. return result;
  14. }
  15. org.junit.runners.ParentRunner#run
  16. @Override
  17. public void run(final RunNotifier notifier) {
  18. EachTestNotifier testNotifier = new EachTestNotifier(notifier, 声明 org.junit.internal.runners.model.EachTestNotifier
  19. getDescription());
  20. try {
  21. Statement statement = classBlock(notifier); 获取org.junit.runners.model.Statement 对象 抽象类封装单元执行的能力提供 提供触发的抽象方法
  22. statement.evaluate(); 触发实际执行单侧逻辑 org.junit.runners.ParentRunner#runChildren
  23. } catch (AssumptionViolatedException e) {
  24. testNotifier.addFailedAssumption(e);
  25. } catch (StoppedByUserException e) {
  26. throw e;
  27. } catch (Throwable e) {
  28. testNotifier.addFailure(e);
  29. }
  30. }
  31. org.junit.runners.ParentRunner#classBlock
  32. protected Statement classBlock(final RunNotifier notifier) {
  33. Statement statement = childrenInvoker(notifier);
  34. if (!areAllChildrenIgnored()) {
  35. statement = withBeforeClasses(statement);
  36. statement = withAfterClasses(statement);
  37. statement = withClassRules(statement);
  38. }
  39. return statement;
  40. }
  41. org.junit.runners.ParentRunner#runChildren
  42. private void runChildren(final RunNotifier notifier) {
  43. final RunnerScheduler currentScheduler = scheduler;
  44. try {
  45. for (final T each : getFilteredChildren()) {
  46. currentScheduler.schedule(new Runnable() {
  47. public void run() {
  48. ParentRunner.this.runChild(each, notifier);
  49. }
  50. });
  51. }
  52. } finally {
  53. currentScheduler.finished();
  54. }
  55. }
  56. ParentRunner.this.runChild(each, notifier); 决定实际的runner的具体执行 (见main函数入口传入的runner类)
  57. org.junit.runners.BlockJUnit4ClassRunner#runChild
  58. @Override
  59. protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
  60. Description description = describeChild(method);
  61. if (isIgnored(method)) {
  62. notifier.fireTestIgnored(description);
  63. } else {
  64. runLeaf(methodBlock(method), description, notifier);
  65. }
  66. }

实例化被测试类对象 并构建 InvokeMethod 对象赋值被测试方法和实例

  1. org.junit.runners.BlockJUnit4ClassRunner#methodBlock
  2. protected Statement methodBlock(FrameworkMethod method) {
  3. Object test;
  4. try {
  5. test = new ReflectiveCallable() {
  6. @Override
  7. protected Object runReflectiveCall() throws Throwable {
  8. return createTest();
  9. }
  10. }.run();
  11. } catch (Throwable e) {
  12. return new Fail(e);
  13. }
  14. Statement statement = methodInvoker(method, test);
  15. statement = possiblyExpectingExceptions(method, test, statement);
  16. statement = withPotentialTimeout(method, test, statement);
  17. statement = withBefores(method, test, statement);
  18. statement = withAfters(method, test, statement);
  19. statement = withRules(method, test, statement);
  20. return statement;
  21. }

实际单元测试以evaluate 最终的反射来完成

  1. org.junit.internal.runners.statements.InvokeMethod
  2. public class InvokeMethod extends Statement {
  3. private final FrameworkMethod testMethod;
  4. private final Object target;
  5. public InvokeMethod(FrameworkMethod testMethod, Object target) {
  6. this.testMethod = testMethod;
  7. this.target = target;
  8. }
  9. @Override
  10. public void evaluate() throws Throwable {
  11. testMethod.invokeExplosively(target);
  12. }
  13. }
  14. org.junit.runners.model.FrameworkMethod#invokeExplosively
  15. public Object invokeExplosively(final Object target, final Object... params)
  16. throws Throwable {
  17. return new ReflectiveCallable() {
  18. @Override
  19. protected Object runReflectiveCall() throws Throwable {
  20. return method.invoke(target, params);
  21. }
  22. }.run();
  23. }

其他

  1. org.junit.runners.model.RunnerScheduler 单元测试job调度
  2. org.junit.runners.BlockJUnit4ClassRunner#methodBlock 子节点 实际执行逻辑构建
  3. 创建被测试类的实例化对象 org.junit.internal.runners.statements.InvokeMethod 赋值methodtarget
  4. org.junit.runners.model.FrameworkMethod#invokeExplosively 完成方法的反射调用
  5. method.invoke(target, params)

发表评论

表情:
评论列表 (有 0 条评论,413人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Junit单元测试

    目录 一、测试分类 1、黑盒测试 2、白盒测试 二、Junit的使用:白盒测试 1、步骤 ①定义一个测试类(测试用例) ②定义测试方法,可独立运行 ③给方法加@

    相关 Junit单元测试

    单元测试 作用: 在写完代码的时候,测试写好的程序是否存在bug。 与一般测试的区别: 一般测试(main方法测试): public class T

    相关 JUnit单元测试

    软件测试有很多分类,从测试的方法上可分为:黑盒测试、白盒测试、静态测试、动态测试等;从软件开发的过程分为:单元测试、集成测试、确认测试、验收、回归等。   在众多的分类中,与

    相关 junit单元测试

    测试就是对所完成功能的校验,查看功能是否有缺陷有漏洞。在工作中,每次做完功能后都要进行测试,测试通过才可以结束该功能的编写。测试是开发中很重要的一部分。 1. Junit\

    相关 JUnit单元测试

      软件测试有很多分类,从测试的方法上可分为:黑盒测试、白盒测试、静态测试、动态测试等;从软件开发的过程分为:单元测试、集成测试、确认测试、验收、回归等。   在众多的分类

    相关 Junit单元测试

    Junit单元测试 单元测试是编写测试代码,应该准确、快速地保证程序基本模块的正确性。 好的单元测试的标准 Junit是Java单元测试框架,已经在Eclipse和Int