junit最原始的版本是多少,junit 源码分析在哪?

junit4 下的所有的testcase都是在Runner下执行的, 可以将Runner理解为junit运行的容器, 默认情况下junit会使用JUnit4ClassRunner作为所有testcase的执行容器。
如果要定制自己的junit, 则可以实现自己的Runner,最简单的办法就是Junit4ClassRunner继承, spring-test, unitils这些框架就是采用这样的做法。
如在spring中是SpringJUnit4ClassRunner, 在unitils中是UnitilsJUnit4TestClassRunner, 一般我们的testcase都是在通过eclipse插件来执行的, eclipse的junit插件会在执行的时候会初始化指定的Runner。初始化的过程可以在ClassRequest中找到。
org.junit.internal.runners.Junit4ClassRunner
package org.junit.internal.
import java.lang.annotation.A
import java.lang.reflect.InvocationTargetE
import java.lang.reflect.M
import java.util.C
import java.util.C
import java.util.I
import java.util.L
import org.junit.runner.D
import org.junit.runner.R
import org.junit.runner.manipulation.F
import org.junit.runner.manipulation.F
import org.junit.runner.manipulation.NoTestsRemainE
import org.junit.runner.manipulation.S
import org.junit.runner.manipulation.S
import org.junit.runner.notification.F
import org.junit.runner.notification.RunN
import org.junit.runners.BlockJUnit4ClassR
* @deprecated Included for backwards compatibility with JUnit 4.4. Will be
removed in the next release. Please use
{@link BlockJUnit4ClassRunner} in place of
{@link JUnit4ClassRunner}.
This may disappear as soon as 1 April 2009
@Deprecated
public class JUnit4ClassRunner extends Runner implements Filterable, Sortable
private final List&Method& fTestM
private TestClass fTestC
//将要测试的TestCase实例Class对象传入
public JUnit4ClassRunner(Class&?& klass) throws InitializationError
fTestClass = new TestClass(klass);
fTestMethods = getTestMethods();
//对要进行测试的方法展开验证
validate();
//获取@test的方法List
protected List&Method& getTestMethods()
return fTestClass.getTestMethods();
//对要进行测试的方法展开验证
protected void validate() throws InitializationError
MethodValidator methodValidator = new MethodValidator(fTestClass);
methodValidator.validateMethodsForDefaultRunner();
methodValidator.assertValid();
public void run(final RunNotifier notifier)
new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable()
public void run()
runMethods(notifier);
}).runProtected();
protected void runMethods(final RunNotifier notifier)
for (Method method : fTestMethods)
invokeTestMethod(method, notifier);
public Description getDescription()
Description spec = Description.createSuiteDescription(getName(), classAnnotations());
List&Method& testMethods = fTestM
for (Method method : testMethods)
spec.addChild(methodDescription(method));
protected Annotation[] classAnnotations()
return fTestClass.getJavaClass().getAnnotations();
protected String getName()
return getTestClass().getName();
protected Object createTest() throws Exception
return getTestClass().getConstructor().newInstance();
protected void invokeTestMethod(Method method, RunNotifier notifier)
Description description = methodDescription(method);
test = createTest();
catch(InvocationTargetException e)
testAborted(notifier, description, e.getCause());
catch(Exception e)
testAborted(notifier, description, e);
TestMethod testMethod = wrapMethod(method);
new MethodRoadie(test, testMethod, notifier, description).run();
private void testAborted(RunNotifier notifier, Description description, Throwable e)
notifier.fireTestStarted(description);
notifier.fireTestFailure(new Failure(description, e));
notifier.fireTestFinished(description);
protected TestMethod wrapMethod(Method method)
return new TestMethod(method, fTestClass);
protected String testName(Method method)
return method.getName();
protected Description methodDescription(Method method)
return Description.createTestDescription(getTestClass().getJavaClass(), testName(method), testAnnotations(method));
protected Annotation[] testAnnotations(Method method)
return method.getAnnotations();
public void filter(Filter filter) throws NoTestsRemainException
for (Iterator&Method& iter = fTestMethods.iterator(); iter.hasNext();)
Method method = iter.next();
if (!filter.shouldRun(methodDescription(method)))
iter.remove();
if (fTestMethods.isEmpty())
throw new NoTestsRemainException();
public void sort(final Sorter sorter)
Collections.sort(fTestMethods, new Comparator&Method&()
public int compare(Method o1, Method o2)
return sorter.compare(methodDescription(o1), methodDescription(o2));
protected TestClass getTestClass()
return fTestC
org.junit.internal.runners.TestClass类
不同于上一节提到的org.junit.runners.model.TestClass类
package org.junit.internal.
import java.lang.annotation.A
import java.lang.reflect.C
import java.lang.reflect.M
import java.util.ArrayL
import java.util.C
import java.util.L
import org.junit.AfterC
import org.junit.B
import org.junit.BeforeC
import org.junit.T
import org.junit.runners.BlockJUnit4ClassR
* @deprecated Included for backwards compatibility with JUnit 4.4. Will be
removed in the next release. Please use
{@link BlockJUnit4ClassRunner} in place of
{@link JUnit4ClassRunner}.
@Deprecated
public class TestClass
private final Class&?& fC
public TestClass(Class&?& klass)
public List&Method& getTestMethods()
return getAnnotatedMethods(Test.class);
List&Method& getBefores()
return getAnnotatedMethods(BeforeClass.class);
List&Method& getAfters()
return getAnnotatedMethods(AfterClass.class);
public List&Method& getAnnotatedMethods(Class&? extends Annotation& annotationClass)
List&Method& results = new ArrayList&Method&();
for (Class&?& eachClass : getSuperClasses(fClass))
Method[] methods = eachClass.getDeclaredMethods();
for (Method eachMethod : methods)
Annotation annotation = eachMethod.getAnnotation(annotationClass);
if (annotation != null && !isShadowed(eachMethod, results))
results.add(eachMethod);
if (runsTopToBottom(annotationClass))
Collections.reverse(results);
private boolean runsTopToBottom(Class&? extends Annotation& annotation)
return annotation.equals(Before.class) || annotation.equals(BeforeClass.class);
private boolean isShadowed(Method method, List&Method& results)
for (Method each : results)
if (isShadowed(method, each))
private boolean isShadowed(Method current, Method previous)
if (!previous.getName().equals(current.getName()))
if (previous.getParameterTypes().length != current.getParameterTypes().length)
for (int i = 0; i & previous.getParameterTypes(). i++)
if (!previous.getParameterTypes()[i].equals(current.getParameterTypes()[i]))
private List&Class&?&& getSuperClasses(Class&?& testClass)
ArrayList&Class&?&& results = new ArrayList&Class&?&&();
Class&?& current = testC
while (current != null)
results.add(current);
current = current.getSuperclass();
public Constructor&?& getConstructor() throws SecurityException, NoSuchMethodException
return fClass.getConstructor();
public Class&?& getJavaClass()
public String getName()
return fClass.getName();
org.junit.internal.runners.MethodValidator类
用于在org.junit.internal.runners.Junit4ClassRunner 类当中进行方法验证
package org.junit.internal.
import java.lang.annotation.A
import java.lang.reflect.M
import java.lang.reflect.M
import java.util.ArrayL
import java.util.L
import org.junit.A
import org.junit.AfterC
import org.junit.B
import org.junit.BeforeC
import org.junit.T
import org.junit.runners.BlockJUnit4ClassR
* @deprecated Included for backwards compatibility with JUnit 4.4. Will be
removed in the next release. Please use
{@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
@Deprecated
public class MethodValidator {
private final List&Throwable& fErrors= new ArrayList&Throwable&();
private TestClass fTestC
//org.junit.internal.runners.JUnit4ClassRunner类中
//validate()方法中调用该构造函数-----第一步
public MethodValidator(TestClass testClass) {
fTestClass = testC
public void validateInstanceMethods() {
validateTestMethods(After.class, false);
validateTestMethods(Before.class, false);
validateTestMethods(Test.class, false);
List&Method& methods= fTestClass.getAnnotatedMethods(Test.class);
if (methods.size() == 0)
fErrors.add(new Exception("No runnable methods"));
public void validateStaticMethods() {
validateTestMethods(BeforeClass.class, true);
validateTestMethods(AfterClass.class, true);
//Junit4ClassRunner类中调用第二步
public List&Throwable& validateMethodsForDefaultRunner() {
//校验无参构造方法
validateNoArgConstructor();
//校验注解方法
validateStaticMethods();
validateInstanceMethods();
//Junit4ClassRunner类中第三步
public void assertValid() throws InitializationError {
if (!fErrors.isEmpty())
throw new InitializationError(fErrors);
public void validateNoArgConstructor() {
fTestClass.getConstructor();
} catch (Exception e) {
fErrors.add(new Exception("Test class should have public zero-argument constructor", e));
//校验要测试的方法 是否静态方法、是否public方法、是否返回值void、是否无参数
//@param annotation 要测试的annotation类
//@param isStatic 是否要求静态方法
private void validateTestMethods(Class&? extends Annotation& annotation,boolean isStatic) {
List&Method& methods= fTestClass.getAnnotatedMethods(annotation);
for (Method each : methods) {
if (Modifier.isStatic(each.getModifiers()) != isStatic) {
String state= isStatic ? "should" : "should not";
fErrors.add(new Exception("Method " + each.getName() + "() "
+ state + " be static"));
if (!Modifier.isPublic(each.getDeclaringClass().getModifiers()))
fErrors.add(new Exception("Class " + each.getDeclaringClass().getName()
+ " should be public"));
if (!Modifier.isPublic(each.getModifiers()))
fErrors.add(new Exception("Method " + each.getName()
+ " should be public"));
if (each.getReturnType() != Void.TYPE)
fErrors.add(new Exception("Method " + each.getName()
+ " should be void"));
if (each.getParameterTypes().length != 0)
fErrors.add(new Exception("Method " + each.getName()
+ " should have no parameters"));
阅读(...) 评论()Junit源码分析_博客园
当前位置: >
>Junit源码分析
Junit源码分析
& 作者:java简单例子 & 来源: 博客园-javaexam2 &
junit是我们平时开发中天天用到的测试框架,为了了解器内部隐藏的机关,特意分析了一下源码,这里我们用的是Junit3.8版本。
1.包的划分
&&junit.awtui,这个是junit的awt实现的ui界面组件
&&junit.extensions这个是junit核心功能之外的扩展点,对TestCase的装饰,Demorator模式的很好的例子
&&junit.framework,这个是junit的核心功能,像我们平时常用的TestCase,TestSuit类都是在这的,还有Assert类,提供了我们测试中常用的断言静态方法
&&junit.runner,这个包下是运行TestCase的核心类,最重要的是TestListener和BaseTestRunner类,这个后面会解释到
&&junit.swingui,这个包的作用和junit.awtui是完全一直的,只不过是用Swing的方式实现而已
&&junit.textui,功能等价与junit.awtui和junit.swingui,junit控制台输出的一个实现,下面的源码解读中,我们以textui包作为ui输出解释
&&从上面的分析可以看出,Junit运行的最小单元是framework+runner+ui-简洁就是美
2.框架的核心类
&&junit的源码非常小,但是设计的非常巧妙,核心类/接口大约有5-6个的样子,通过分析,我们可以得出一下的核心类图
&&Test接口:这个是最顶层的测试实体抽象,接口中只定义了两个方法,countTestCases()表示当前测试实体有多少个测试用例,另一此文来自: 马开东博客
转载请注明出处 网址:
相关阅读:
来源:(微信/QQ:,微信公众号:makaidong-com) &&&&&& 欢迎分享本文,转载请保留出处!
&&&&&& 【原文阅读】:
上一篇:没有了
【相关文章】
每日最新文章
每日最热文章
本周最热文章
本月最热文章
本年最热文章
Powered by
Copyright &
www.makaidong.com, All Rights Reserved从执行流程分析Junit4源码 - 简书
从执行流程分析Junit4源码
阅读前提条件,了解JUnit4的基本用法。代码版本:
从执行流程来分析
一般情况下使用IDE开发项目通过鼠标很容易执行测试方法和类,分析源码的话我们就要找到程序的入口,一步一步看程序是怎么跑起来的,下面我们先看如何在不依赖IDE的情况下让测试类跑起来。
手动运行方式
程序运行入口类:JUnitCore。该类有两种方式来执行测试类:
mian方法:即最常见的public static void main(String... args),通过在命令行输入要执行测试的类作为参数来运行测试方法。
通过使用runClasses(Class&?&... classes)方法,举个栗子:
public class Test {
public static void main(String[] args) {
Result result = JUnitCore.runClasses(RunTest.class);
//RunTest即包含测试方法的类
for (Failure failure : result.getFailures()) { // 对于执行失败的情况打印失败信息
System.out.println(failure.toString());
两种方式的执行流程大致相同,最终都调用到了JUnitCore#run(Request request)方法,这里我们以第二种方式来分析执行流程。
这里只分析了关键的代码和类,并没有贴出全部的代码,详细的内容要参考源码!
关键类(可以暂时忽略这些类,在调用流程分析中如果遇到哪个类不明白再返回来看说明):
Runner:用来执行测试,以RunNotifier的形式发布通知。
ParentRunner继承自Runner,提供了作为一个Runner的大部分功能,可以进行过滤和分类,处理BeforeClass,AfterClass还有ClassRule,创建复合的Description,并按照顺序来执行多个测试。不过仍需要子类来构造并真正实现执行需要被Run的对象,
BlockJUnit4ClassRunner:继承自ParentRunner是默认的测试类的runner。
Suite:作为一个runner,通过它可以包含多个类来进行测试执行。
RunnerBuilder:用来给测试类创建runner。
AllDefaultPossibilitiesBuilder: 主要是在runnerForClass(Class&?& testClass)方法中根据注解标识返回合适的RunnerBuilder。比如,如过被测试的方法只被@Test标识,那么就会返回JUnit4Builder。
JUnit4Builder:默认情况下被调用,创建返回BlockJUnit4ClassRunner实例。
Request :对被运行的测试类的抽象描述。
Computer:根据RunnerBuilder用来创建出runner和suite。
Statement:一个接口,代表将要被运行的一个或多个动作,他只有一个方法evaluate(),用来执行。
1. 传入测试类
传入测试类调用JUnitCoure#runClasses(Class&?&... classes)方法。
2. 创建Request对象
之后调用到run(Computer computer, Class&?&... classes)方法,传入的是直接new的Computer对象。在该方法中通过Request.classes(Computer computer, Class&?&... classes)方法创建并返回了一个Request对象,
其代码如下:
public static Request classes(Computer computer, Class&?&... classes) {
AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true);
Runner suite = computer.getSuite(builder, classes);
return runner(suite);
} catch (InitializationError e) {
return runner(new ErrorReportingRunner(e, classes));
public static Request runner(final Runner runner) {
return new Request() {
public Runner getRunner() {
可以看出返回的request内部的runner是通过computer的getsuite方法得出的,
再看Computer#getSuite(final RunnerBuilder builder, Class&?&[] classes)方法:
public Runner getSuite(final RunnerBuilder builder,
Class&?&[] classes) throws InitializationError {
return new Suite(new RunnerBuilder() {
public Runner runnerForClass(Class&?& testClass) throws Throwable {
//这里的builder参数实际上是AllDefaultPossibilitiesBuilder
return getRunner(builder, testClass);
}, classes);
protected Runner getRunner(RunnerBuilder builder, Class&?& testClass) throws Throwable {
return builder.runnerForClass(testClass);
通过上面几个方法的调用可以得出,返回的runner依赖着AllDefaultPossibilitiesBuilder。
3. 获取真正的Runner
调用run(Runner runner)方法其中的runner参数是通过Request的getRunner()方法得来的。由2中的代码可知,这里得出的runner是从Computer#getSuite方法中得出的,该方法最终调用到的是传入的AllDefaultPossibilitiesBuilder,通过他的runnerForClass方法返回出真正的runner,代码如下:
public Runner runnerForClass(Class&?& testClass) throws Throwable {
List&RunnerBuilder& builders = Arrays.asList(
ignoredBuilder(),
annotatedBuilder(),
suiteMethodBuilder(),
junit3Builder(),
junit4Builder());
//通过for循环过滤出真正的runner
for (RunnerBuilder each : builders) {
Runner runner = each.safeRunnerForClass(testClass);
if (runner != null) {
一般情况下如果方法只被@Test标记,将返回一个JUnit4Builder,其类代码如下:
public class JUnit4Builder extends RunnerBuilder {
public Runner runnerForClass(Class&?& testClass) throws Throwable {
return new BlockJUnit4ClassRunner(testClass);
在这里我们知道了最终得到的runner是BlockJUnit4ClassRunner的一个实例,并向它传入了我们的测试类。
4. 方法真正被run的入口
回到JUnitCore类,跟着代码走,下一步调用run(Runner runner)方法,接下来是关键,到了测试方法被真正执行的地方:
public Result run(Runner runner) {
Result result = new Result();
RunListener listener = result.createListener();
notifier.addFirstListener(listener);
notifier.fireTestRunStarted(runner.getDescription());
runner.run(notifier);
notifier.fireTestRunFinished(result);
} finally {
removeListener(listener);
我们先看执行,把RunListener和Result放一边,在方法内部调用到了Runner的run(notifier)方法,到这里我们知道,真正的Runner是BlockJUnit4ClassRunner, 它的run方法在其父类ParentRunner中,代码如下:
public void run(final RunNotifier notifier) {
EachTestNotifier testNotifier = new EachTestNotifier(notifier,
getDescription());
testNotifier.fireTestSuiteStarted();
Statement statement = classBlock(notifier);
statement.evaluate(); // 这里这行的时候是执行了每个方法的evaluate,从而使测试方法都被执行。
} catch (AssumptionViolatedException e) {
testNotifier.addFailedAssumption(e);
} catch (StoppedByUserException e) {
} catch (Throwable e) {
testNotifier.addFailure(e);
} finally {
testNotifier.fireTestSuiteFinished();
刨除其他干扰,这段代码有两句最为关键Statement statement = classBlock(notifier); statement.evaluate();classBlock方法返回了包含执行内容的Statement,然后通过evaluate方法得到了执行,也就是我们的测试类被执行了。接下来我们来分析这两行代码。
5. 获取所有需要被执行的测试方法
classBlock方法如下:
protected Statement classBlock(final RunNotifier notifier) {
Statement statement = childrenInvoker(notifier);
if (!areAllChildrenIgnored()) {
statement = withBeforeClasses(statement);
statement = withAfterClasses(statement);
statement = withClassRules(statement);
这里获取到了处理所有测试方法的对象,还根据情况写入了Before,After,Rule条件。我们再看他是如何获取到一系列的测试方法的:
protected Statement childrenInvoker(final RunNotifier notifier) {
return new Statement() {
public void evaluate() {
runChildren(notifier);
我们可以看到最终返回的Statement是一个可执行runChildren方法的Statement,所以最终的执行也就是执行runChildren方法,
private void runChildren(final RunNotifier notifier) {
final RunnerScheduler currentScheduler =
for (final T each : getFilteredChildren()) {
currentScheduler.schedule(new Runnable() {
public void run() {
ParentRunner.this.runChild(each, notifier);
} finally {
currentScheduler.finished();
这里有一个getFilteredChildren方法,在其方法内部调用到了getChildren方法,代码如下:
protected List&FrameworkMethod& getChildren() {
return computeTestMethods();
protected List&FrameworkMethod& computeTestMethods() {
return getTestClass().getAnnotatedMethods(Test.class);
在这里终于看到了我们的注解类Test被用到了,返回了包含@Test注解方法的包装类:FrameworkMethod。接下来的runChild方法即是执行这个FrameworkMethod。
6. 方法最终被执行
分析runChild方法
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
Description description = describeChild(method);
if (isIgnored(method)) {
notifier.fireTestIgnored(description);
statement = methodBlock(method);
catch (Throwable ex) {
statement = new Fail(ex);
runLeaf(statement, description, notifier);
可以看到这里仍然是用的Statement来代表要被执行的对象,这里有两个关键方法methodBlock用来构建出具体的statement和真正执行statement的runLeaf方法.
首先看methodBlock的调用流程:
protected Statement methodBlock(final FrameworkMethod method) {
·····省略部分无关代码·····
Statement statement = methodInvoker(method, test);
statement = possiblyExpectingExceptions(method, test, statement);
statement = withPotentialTimeout(method, test, statement);
statement = withBefores(method, test, statement);
statement = withAfters(method, test, statement);
statement = withRules(method, test, statement);
protected Statement methodInvoker(FrameworkMethod method, Object test) {
return new InvokeMethod(method, test);
public class InvokeMethod extends Statement {
private final FrameworkMethod testM
private final O
public InvokeMethod(FrameworkMethod testMethod, Object target) {
this.testMethod = testM
this.target =
public void evaluate() throws Throwable {
testMethod.invokeExplosively(target);
public Object invokeExplosively(final Object target, final Object... params)
throws Throwable {
return new ReflectiveCallable() {
protected Object runReflectiveCall() throws Throwable {
return method.invoke(target, params);
可以看到最终返回的Statement中执行方法终于调用到了method.invoke(Object obj, Object... args),没错这里终于回到了Java中的反射,就是在这里最终执行了目标方法。好了,离最后的成功只差几小步了,接下来就是发出调用执行了,我们看runLeaf方法:
protected final void runLeaf(Statement statement, Description description,
RunNotifier notifier) {
EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
eachNotifier.fireTestStarted();
statement.evaluate();
} catch (AssumptionViolatedException e) {
eachNotifier.addFailedAssumption(e);
} catch (Throwable e) {
eachNotifier.addFailure(e);
} finally {
eachNotifier.fireTestFinished();
好,在runLeaf中传入了statement, 这个statement在methodBlock方法中被构造完成,我们知道他的evalute方法是由InvokeMethod类来重写的,并最终通过反射执行了需要被测试的方法,所以执行从此开始。
7. 执行流程回顾
所以最终的执行终于清晰了:在run方法中获取到了被执行的Statement,并执行它,这个statement执行的是ParentRunner#runChildren方法,runChildren循环为每个方法调用BlockJUnit4ClassRunner#runChild,在runChild内部继续为方法创建了一个Statement,并在InvokeMethod类中重写statement的evalute方法然后传入ParentRunner#runLeaf方法最终得到了执行。嗯,到此为止!
我们在这里只是简单的分析了通过JUnitCore类来执行测试类的调用流程,虽然最后都是通过反射来进行的调用,但是JUnit4框架为此创建了大量的类,因为JUnit4有大量的扩展功能,不只是一个简单的@Test注解而已。其实分析完执行流程才只是刚刚开始,更有价值的地方在于体会JUnit4整个框架的架构和其中运用到的设计模式,不只停留在知道作者创建了哪些类,还要站在设计的角度考虑作者为什么要这样写,比如为什么要创建Computer,RunnerBuilder,Runeer,Statement这么多类来执行最终的反射调用,这样做有什么好处,因此还需要我们进一步深入探索,学习。
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
百战程序员_ Java1573题 QQ群:034603 掌握80%年薪20万掌握50%年薪10万 全程项目穿插, 从易到难,含17个项目视频和资料持续更新,请关注www.itbaizhan.com 国内最牛七星级团队马士兵、高淇等11位十年开发经验专...
JUnit Intro Android基于JUnit Framework来书写测试代码。JUnit是基于Java语言的流行的、广泛被使用的测试框架,当前最新的版本是JUnit4。相对于之前的版本而言,JUnit4允许开发者使用更清晰、简洁、灵活的方式来构建测试代码。Andr...
1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法。 1、一个&.java&源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个publ...
1.写在前面 基于junit 4.12版本,对junit源码阅读之后的理解和总结,如有不正确的地方,请多指正 2.junit的模块 根据自己对源码的理解,junit大体可以划分为以下几个模块 1.Request负责发送测试指令2.Runner负责运行测试用例3.Runner...
自小,我是羡慕那些文人墨客的。笔上的功夫,炉火纯青。一个个中国汉字历经他们之手便大放异彩。这是一种本事,一种不会因时间的流逝而淡化的本事。一种让历代文人终其一生研究的本事。我是想拥有这种本事的。究其为何,大概是我也想成为那个让人心生羡慕的人吧。抱着这种想法,我曾尝试,...
图片发自简书App 高卧、静坐、尝酒、试茶、 阅书、临帖、对画、诵经、 咏歌、鼓琴、焚香、莳花、 候月、听雨、望云、瞻星、 负暄、赏雪、看鸟、观鱼、 漱泉、濯足、倚竹、抚松、 远眺、俯瞰、散步、荡舟、 游山、玩水、访古、寻幽、 消寒、避暑、随缘、忘愁、 慰亲、习业、为善、布施。
1.早起背金刚经,然后7遍心经21遍心咒,回向众生,回向儿子学业,自己的事业,父母的身体,老公的减肥、以及老公的经济 2.反省自己对孩子的教育态度和教育方式。开始积极寻求更好的方式。 3.仔细聆听了麦克格西老师的第三次演讲,并把笔记分享给朋友。 4.开始学习书写六时书,主要...
当王嘉尔接到他那个没怎么见过面的室友发来的语音的时候,外面正下着倾盆大雨。 “王嘉尔,过来接我……快点……”白敬亭的声音听起来很虚弱。然后发了一个定位。 肯定是出事了。 王嘉尔几口吃完剩下的外卖,穿上外套就冲出去,同时回了条:“哥!你等着我马上过去!”骑着摩托车就往那边赶。...}

我要回帖

更多关于 junit源码解析 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信