`

Java EE 单元测试

    博客分类:
  • Java
阅读更多

觉得测试 Java EE 应用程序太困难、不方便或者太复杂?通过阅读本文,您将了解现实情况并非如此,同时还将了解如何高效进行单元测试。

测试是 Java Platform, Enterprise Edition (Java EE) 仍存的神秘领域之一。人们常常错误地认为 Java EE 应用程序的测试比较困难、不方便或者太复杂。从五年多前 Java EE 5 发布以来,实际情况并非人们所认为的那样。在本文中,我将探究单元测试。在后续文章中,我将探讨集成测试和嵌入式容器测试。

:您可以在这里找到用于本文的 Maven 3 项目 TestingEJBAndCDI,已使用 NetBeans 7 和 GlassFish v3.x 对其进行过测试。

向 Oracle 询问 Java 的未来

我将使用一个“oracle”应用程序,借助后台的一些顾问,它能够预测 Java 的未来。需要澄清一下,“oracle”在此处另有他义:

“在古代,oracle 是在神的启示下,能够提出明智的忠告或具有先知先觉能力,可以预言或预知未来的人或机构。因此,这是一种占卜。”

在现代,即便一个 oracle 也需要依靠表示状态传输 (REST) 来公开他的预言(参见清单 1)。OracleResource 是一个 Enterprise JavaBeans (EJB) 3.1 bean,通过用于 RESTful Web 服务的 Java API (JAX-RS) 作为上下文和依赖注入 (CDI) 托管 bean 的 REST 资源和网关来提供。OracleResource 维护一个注入 consultant 池 (Instance<Consultant> company),并请求第一个 consultant 预测 Java 的未来。

 

01 @Path("javafuture")
02 @Stateless
03 public class OracleResource {
04  
05     @Inject
06     Instance<Consultant> company;
07     @Inject
08     Event<Result> eventListener;
09  
10     @GET
11     @Produces(MediaType.TEXT_PLAIN)
12     public String predictFutureOfJava() {
13         checkConsultantAvailability();
14         Consultant consultant = getConsultant();
15         Result prediction = consultant.predictFutureOfJava();
16         eventListener.fire(prediction);
17  
18         if (JAVA_IS_DEAD.equals(prediction)) {
19             throw new IllegalStateException("Please perform a sanity / reality check");
20         }
21  
22         return prediction.name();
23     }
24  
25     void checkConsultantAvailability() {
26         if (company.isUnsatisfied()) {
27             throw new IllegalStateException("No consultant to ask!");
28         }
29     }
30  
31     Consultant getConsultant() {
32         for (Consultant consultant : company) {
33             return consultant;
34         }
35          
36         return null;
37     }
38 }

 

清单 1:作为 CDI 托管 Bean 的 REST 资源和网关的 EJB 3.1 Bean

Consultant 是一个由 Blogger、ReasonableConsultant 和 SmartConsultant 实现的 Java 接口。OracleResource 只是选择第一个 Consultant,向其询问 Java 的未来。除了 JAVA_IS_DEAD(会引起 IllegalStateException)外,所有答案均可接受。通常,您会使用 javax.inject.Qualifier 明确您的选择,但 javax.enterprise.inject.Instance 的测试比较困难,因此我使用 javax.enterprise.inject.Instance 来使测试更加“有趣”。

 

1 public class Blogger implements Consultant {
2  
3     @Override
4     public Result predictFutureOfJava() {
5  
6         return Result.JAVA_IS_DEAD;
7  
8     }
9 }

 

清单 2:Blogger Consultant 实现

所有预言都作为事务事件进行分配。每个预言均在 EJB 容器启动的独立事务中执行。这是一种约定;无需为此进行额外配置。

PredictionAudit EJB 3.1 bean 接收事件,它使用 Java Persistence API (JPA) 2 保存所有成功的和失败的预言,因为已知有些 consultant 会回滚他们的结论(参见清单 3)。

 

01 @Stateless
02 public class PredictionAudit {
03  
04     @PersistenceContext
05     EntityManager em;
06  
07     public void onSuccessfulPrediction(@Observes(during = TransactionPhase.AFTER_SUCCESS) Result result) {
08         persistDecision(result, true);
09     }
10  
11     public void onFailedPrediction(@Observes(during = TransactionPhase.AFTER_FAILURE) Result result) {
12         persistDecision(result, false);
13     }
14  
15     void persistDecision(Result result, boolean success) {
16         Prediction prediction = new Prediction(result, success);
17         em.persist(prediction);
18     }
19  
20     public List<Prediction> allDecisions() {
21         return this.em.createNamedQuery(Prediction.findAll).getResultList();
22     }
23 }

 

清单 3:事件驱动的 PredictionAudit

CDI 事件巧妙地将 OracleResource 与 PredictionAudit 分离,但同时也使测试变得更加困难。无论事务是提交还是回滚,对每个预言均保存 JPA 2 实体 Prediction(参见清单 4)。

 

01 @Entity
02 @XmlRootElement
03 @XmlAccessorType(XmlAccessType.FIELD)
04 @NamedQuery(name = Prediction.findAll, query = "Select d from Prediction d")
05 public class Prediction {
06  
07     public final static String PREFIX ="com.abien.testing.oracle.entity.Prediction.";
08     public final static String findAll = PREFIX + "findAll";
09     @Id
10     @GeneratedValue
11     @XmlTransient
12     private long id;
13     @Column(name = "prediction_result")
14     @Enumerated(EnumType.STRING)
15     private Result result;
16     @Temporal(TemporalType.TIME)
17     private Date predictionDate;
18     private boolean success;
19  
20     public Prediction() {
21         this.predictionDate = new Date();
22     }
23  
24     public Prediction(Result result, boolean success) {
25         this();
26         this.result = result;
27         this.success = success;
28     }
29      
30     //bookkeeping methods omitted
31 }

 

清单 4:JPA 2 实体结论 

Maven 3 与单元测试 — 开始之前

Java EE 6 应用程序的单元测试没什么特别之处。只需将 JUnit 库添加到 pom.xml 文件中(参见清单 5),将您的类放到 src/test/java 目录中。在标准 Maven 生命周期 (mvn clean install) 期间,将自动执行所有 JUnit 测试。 

 

1 <dependency>
2   <groupId>junit</groupId>
3   <artifactId>junit</artifactId>
4   <version>4.8.2</version>
5   <scope>test</scope>
6 </dependency>

 

清单 5:在 pom.xml 中包括 JUnit 库

加载标准 Maven 原型包含的 Java EE 6 API 类时将收到一条奇怪的错误(参见清单 6)。 

1 <dependency>
2  <groupId>javax</groupId>
3  <artifactId>javaee-web-api</artifactId>
4  <version>6.0</version>
5  <scope>provided</scope>
6 </dependency>

 

清单 6:对 API 的引用不可用

Maven 信息库中的标准 Java EE 6 API 经过一个工具的处理,该工具从字节码中删除方法的主体实现,从而使 javaee-web-api 依赖对单元测试不可用。从 Java EE 6 API 加载类的任何尝试都将导致类似下面的错误:

 

1 Absent Code attribute in method that is not native or abstract in class filejavax/enterprise/util/TypeLiteral
2  
3 java.lang.ClassFormatError:Absent Code attribute in method that is not native or abstract in class file javax/enterprise/util/TypeLiteral
4  
5  at java.lang.ClassLoader.defineClass1(Native Method)
6  at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)

 

清单 7:从 Java EE 6 API 加载类时导致的错误

您应该用应用程序供应商的实现替换 Java EE 6 API 类。对 GlassFish v3.1,最方便的方法是在嵌入式容器上使用单个依赖: 

 

1 <dependency>
2  <groupId>org.glassfish.extras</groupId>
3  <artifactId>glassfish-embedded-all</artifactId>
4  <version>3.1</version>
5  <scope>provided</scope>
6 </dependency>

 

清单 8:Java EE 6 API 替换

当然,您可以为 JUnit 测试或编译挑选 CDI、JPA、EJB 等库,或者使用 JBoss 或 Geronimo Maven 镜像中的有效替代品。

为何选择 Mockito?

Mockito 是一个易用的开源模拟库。Mockito 能够从类或接口创建“智能代理”(也称为模拟)。虽然这些代理不附带任何行为,但它们仍然十分有用。您可以调用方法,但只会返回默认值,或空值。创建这些模拟后,将使用 when(mock.getAnswer()).then(42) 语法记录它们的行为。

Mockito 非常适合“模拟”各种难以实现的类、资源或服务。您只要了解一个 org.mockito.Mockito 类就可以开始学习使用 Mockito 了。when-then“领域专用语言”由来自 Mockito 类的静态方法组成。对 org.mockito.Mockito 类的文档注释很好。事实上,由 org.mockito.Mockito 类中的 JavaDoc 标记生成了完整的文档集。

使用 Mockito 对 Java EE 6 进行单元测试

PredictionAudit 将根据事务结果设置“success”标记,并使用 EntityManager 保存 Prediction 实体。要精确测试 PredictionAudit 类,必须“模拟”EntityManager。我们将只测试 EntityManager#persist 方法是否接收正确参数,而不测试是否真正保存 Prediction 实体。(在后续文章中,我们将探讨对 PredictionAudit 与实际 JPA EntityManager 功能间交互的集成测试。)

使用改进的静态 mock(EntityManager.class) 方法创建模拟出的 EntityManager 实例。

 

01 import static org.mockito.Mockito.*;
02  
03 public class PredictionAuditTest {
04  
05     private PredictionAudit cut;
06  
07     @Before
08     public void initializeDependencies() {
09         cut = new PredictionAudit();
10         cut.em = mock(EntityManager.class);
11     }
12  
13     @Test
14     public void savingSuccessfulPrediction() {
15         final Result expectedResult = Result.BRIGHT;
16         Prediction expected = new Prediction(expectedResult, true);
17         this.cut.onSuccessfulPrediction(expectedResult);
18         verify(cut.em, times(1)).persist(expected);
19     }
20  
21     @Test
22     public void savingRolledBackPrediction() {
23         final Result expectedResult = Result.BRIGHT;
24         Prediction expected = new Prediction(expectedResult, false);
25         this.cut.onFailedPrediction(expectedResult);
26         verify(cut.em, times(1)).persist(expected);
27     }
28 }

 

清单 9:PredictionAudit 的单元测试与模拟

模拟出的 EntityManager 实例直接注入到默认的可见域 PredictionAudit#em 中。在 savingSuccessfulPrediction 测试方法中(参见清单 9),创建了一个 Result 实例并将它传递给 onSuccessfulPrediction 方法,该方法创建 Prediction 实例并调用 EntityManager#persist(参见清单 3)。静态方法 verify(cut.em,times(1)).persist(expected) 验证是否使用所期望的参数仅调用过一次 EntityManager#persist 方法。

一个更复杂的模拟案例

EJB 3.1 OracleResource bean 的 javax.enterprise.event.Event 和 javax.enterprise.inject.Instance 这两个实例的注入对于测试来说更为有趣。将使用 Mockito#mock 方法再次执行 CDI 依赖项的初始化和模拟(参见清单 10)。

 

01 public class OracleResourceTest {
02  
03     private OracleResource cut;
04  
05     @Before
06     public void initializeDependencies() {
07         this.cut = new OracleResource();
08         this.cut.company = mock(Instance.class);
09         this.cut.eventListener = mock(Event.class);
10 }

 

清单 10:CDI 依赖项的初始化和模拟

我们从 helper 方法 checkConsultantAvailability 的测试开始,该方法验证顾问的可用性。如果未找到 Consultant 实现,我们希望生成 IllegalStateException。静态方法 Mockito#when 记录 Mockito#mock 方法所返回实例期待的行为。我们只需为 Instance#isUnsatisfied 返回 true,并且期待一个 IllegalStateException:

 

1 @Test(expected = IllegalStateException.class)
2 public void checkConsultantAvailabilityWithoutConsultant(){
3     when(this.cut.company.isUnsatisfied()).thenReturn(true);
4     this.cut.checkConsultantAvailability();
5 }

 

清单 11:预先记录模拟行为

如果 Consultant 给出一个很荒唐的预言,EJB bean OracleResource 将抛出一个 IllegalStateException。Consultant 接口的 Blogger 实现始终返回 JAVA_IS_DEAD,这将引发 IllegalStateException。为测试这一行为,我们必须模拟出 javax.enterprise.inject.Instance 返回的 Iterator:

 

1 Iterator mockIterator(Consultant consultant) {
2     Iterator iterator = mock(Iterator.class);
3     when(iterator.next()).thenReturn(consultant);
4     when(iterator.hasNext()).thenReturn(true);
5     return iterator ;
6 }

 

清单 12:模拟出 Iterator

我们改变 Instance 的行为使其返回模拟的 Iterator 实例:

 

1 @Test(expected = IllegalStateException.class)
2 public void unreasonablePrediction() {
3     Consultant consultant = new Blogger();
4     Iterator iterator = mockIterator(consultant);
5     when(this.cut.company.iterator()).thenReturn(iterator);
6     this.cut.predictFutureOfJava();
7 }

 

清单 13:返回模拟出的 Iterator

模拟出实例将使您可以控制实际使用哪个 Consultant 实现。在我们的案例中,我们可以仅使用 Blogger 实现来检查是否正确抛出了 IllegalStateException。您也可以创建一个 Consultant 模拟,返回这个模拟,而不是返回实际的 Blogger 实例。这种做法尤其适用于 Java EE 平台上具有很强依赖性的 Consultant 实现。

还模拟出了 Event 实例,这使您可以验证已执行的方法调用: 

 

01 @Test
02 public void unreasonablePredictionFiresEvent() {
03     Consultant consultant = new Blogger();
04     Result expectedResultToFire = consultant.predictFutureOfJava();
05     Iterator iterator = mockIterator(consultant);
06     when(this.cut.company.iterator()).thenReturn(iterator);
07  
08     try {
09         this.cut.predictFutureOfJava();
10     catch (IllegalStateException e) {
11     }
12  
13     verify(this.cut.eventListener, times(1)).fire(expectedResultToFire);
14 }

 

清单 14:测试 Event#fire 调用

对失败案例的测试稍微麻烦一点。我们先接受 IllegalStateException,然后检查实际上是否调用了 Event#fire 方法。

与 Java SE 类似

Java EE 6 应用程序的单元测试与测试 Java Platform, Standard Edition (Java SE) 没有区别。Java EE 6 组件只是一些带批注的类。您无需以特殊的方式对待它们;而是应该重点关注业务逻辑的验证。

在容器内部测试所有内容是一种常见的错误做法。即使是 Java EE 6 容器也要花数秒钟的时间来启动和部署应用程序。在容器中测试业务逻辑不仅浪费时间,还会带来不必要的复杂性。在 Java EE 6 中,您应该始终将单元测试与集成测试分开。甚至应该分别执行单元测试和集成测试。使用模拟出的环境进行真正的单元测试快如闪电。PredictionAuditTest 和 OracleResourceTest 的执行甚至用不了半秒钟:

 

01 -------------------------------------------------------
02  
03  T E S T S
04  
05 -------------------------------------------------------
06  
07 Running com.abien.testing.oracle.boundary.OracleResourceTest
08  
09 Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.254 sec
10  
11 Running com.abien.testing.oracle.control.PredictionAuditTest
12  
13 Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.025 sec
14  
15 Results :
16  
17 Tests run: 8, Failures: 0, Errors: 0, Skipped: 0

 

清单 15:测试结果

最常见错误的观点:您需接口来进行模拟

接口的引入往往是由模拟造成的。然而,现代框架根本不需要接口就可实现模拟。可以直接由传统 Java 对象 (POJO) 类方便地创建模拟。PredictionArchiveResource 使用直接注入的 PredictionAudit 类(参见清单 16)。

 

01 @Path("predictions")
02 @Stateless
03 public class PredictionArchiveResource {
04  
05     @EJB
06     PredictionAudit audit;
07  
08     @GET
09     @Produces(MediaType.APPLICATION_JSON)
10     public List<Prediction> allPredictions(@DefaultValue("5"@QueryParam("max")int max) {
11  
12         List<Prediction> allPredictions = audit.allPredictions();
13  
14         if (allPredictions.size() <= max) {
15             return allPredictions;
16         else {
17             return allPredictions.subList(0, max);
18         }
19     }
20 }

 

清单 16:POJO 类注入

尽管 PredictionAudit 是一个类而不是一个接口,但也可以轻松地模拟它。为了测试返回列表的大小限制,对 PredictionAudit 类进行了全面模拟(参见清单 17)。

 

01 public class PredictionArchiveResourceTest {
02  
03     PredictionArchiveResource cut;
04  
05     @Before
06     public void initialize() {
07         this.cut = new PredictionArchiveResource();
08         this.cut.audit = mock(PredictionAudit.class);
09     }
10  
11     @Test
12     public void allDecisionsWithMaxLesserReturn() throws Exception {
13         int expectedSize = 2;
14         List<Prediction> prediction = createDecisions(expectedSize);
15         when(this.cut.audit.allPredictions()).thenReturn(prediction);
16         List<Prediction> allDecisions = this.cut.allPredictions(3);
17         assertThat(allDecisions.size(), is(expectedSize));
18     }
19  
20     @Test
21     public void allDecisionsWithMaxGreaterReturn() throws Exception {
22         int max = 5;
23         int expected = 3;
24         List<Prediction> prediction = createDecisions(max);
25         when(this.cut.audit.allPredictions()).thenReturn(prediction);
26         List<Prediction> allDecisions = this.cut.allPredictions(expected);
27         assertThat(allDecisions.size(), is(expected));
28     }
29  
30     @Test
31     public void allDecisionsWithMaxEqualReturn() throws Exception {
32         //obvious code omitted
33     }
34  
35     List<Prediction> createDecisions(final int nr) {
36         return new ArrayList<Prediction>() {
37             {
38                 for (int i = 0; i < nr; i++) {
39                     add(new Prediction(Result.BRIGHT, true));
40                 }
41             }
42         };
43     }
44 }

 

清单 17:Java 类模拟

PredictionArchiveResource 类中唯一值得关注的业务逻辑就是列表大小的限制(参见清单 16)。QueryParameter 的最大值用于计算子列表的大小。PredictionArchiveResource 模拟实例允许返回任意大小的 List<Prediction>。无需访问 JPA 层(甚至数据库)就能控制列表的内容和大小将会极大简化测试。模拟还显著加快了测试执行速度。数据库访问需要几秒钟,而几毫秒就可完成对模拟的访问。

Java EE 6 使接口成为可选。您可以注入类(CDI 托管 bean 和 EJB bean),而不是接口,这丝毫不会牺牲任何“企业”特性。也完全不必为了模拟而使用接口。使用普通类(而非接口)作为一般的构建块,不仅可以使生产代码的实现更加精简,而且还能简化测试。您不必决定是模拟类还是接口。

总结

至此,我们仅测试了对象和方法的内部功能。为使测试尽可能简单,完全模拟出了周围的基础架构。我们的测试工作完全符合单元测试的定义:“在计算机编程中,单元测试是一种方法,使用这种方法对源代码的每个单元进行测试,以确定它们是否适用。单元是指应用程序最小的可测试部分。在过程编程中,单元可能是一个单独的函数或过程。在面向对象的编程中,单元通常是一个方法……”(http://en.wikipedia.org/wiki/Unit_testing)

尽管我们所有单元测试的结果均“成功”,但我们仍然不清楚应用程序是否可部署。JPA 2 映射错误、不一致的 persistence.xml 或 JPA 查询拼写错都根本无法使用也不应使用经典单元测试来测试。诸如 CDI 事件传递、复杂依赖注入或 JPA 查询之类与基础架构相关的逻辑只能使用集成测试在类似于生产的环境中进行测试。在后续文章中,我将探讨集成测试的方方面面。

另请参见

顾问兼作家 Adam Bien 是 Java EE 6 和 7、EJB 3.X、JAX-RS、CDI 和 JPA 2.X JSR 专家组成员。他从 JDK 1.0 就开始使用 Java 技术,并在几个大型项目中使用了 servlet/EJB 1.0,目前是 Java SE 和 Java EE 项目的架构师和开发人员。他编辑了多本关于 JavaFX、J2EE 和 Java EE 的图书,并且是《Real World Java EE Patterns—Rethinking Best Practices》《Real World Java EE Night Hacks—Dissecting the Business Tier》两本书的作者。Adam 还是 Java Champion 和 JavaOne 2009 Rock Star。

7
7
分享到:
评论

相关推荐

    从Java走向Java+EE+.rar

    第1章 Java EE的基本知识 1 1.1 Java EE的出现及其...23.3 利用JUnit进行单元测试 324 23.4 利用StrutsTestCase对Struts进行测试 328 23.5 压力测试和JMeter 334 23.6 其他开源测试工具 339 23.7 小结 343

    Java测试新技术TestNG和高级概念.part1

    展示了如何测试应用程序元素,包括Java EE APls、数据库、Web页面和XML文件。 展示了高级技术:测试部分失败、工厂、依赖关系测试、远程调用、基于集群的测试服务器群等。 介绍了在Eclipse和IDE中安装TestNG插件。 ...

    BeanTest:Java EE应用程序的Bean测试

    在标准环境中运行单元测试时,它使用CDI容器解析EJB或资源之类的依赖项。 使用名称“ Bean Testing”,因为它与适当的单元测试无关。 但是,反馈速度非常接近于单元测试,并且测试看起来也无法区分。 主要优点: ...

    javaee-testing:单元测试 com Java EE

    javaee-测试使用 Java EE 进行单元测试演示链接: 参考: JUnit - Arquillian - DBUnit- Selenium - Cucumber -

    Java测试新技术TestNG和高级概念.part2

    展示了如何测试应用程序元素,包括Java EE APls、数据库、Web页面和XML文件。 展示了高级技术:测试部分失败、工厂、依赖关系测试、远程调用、基于集群的测试服务器群等。 介绍了在Eclipse和IDE中安装TestNG插件。 ...

    try_java_ee7:使用 Java EE 7 构建 Web 应用程序

    单元测试 使用 CDI 单元进行测试 由 Mockito 测试 使用嵌入式数据库进行测试 其他 引导程序 3.1 网络罐 未来预计使用什么 EJB 3.1 JMS(最好) JAX-RS 网络套接字 批量支持 嵌入式容器 并发(最好)

    JavaME下的单元测试开发之JMUnit篇

    本系列文章(两篇)正是想详细探讨J2MEUnit和JMUnit这两个开源框架在JavaME单元测试开发中的应用。一、引言如今,JUnit测试正在逐渐成为大多数Java标准版(SE)和企业版(EE)应用程序开发中的基本组成部分-对于那些积极...

    java2ee项目原文件

    04 在Eclipse中进行资源构建----Ant使用实例 ... 09 JUnit开发实例----图书管理系统的单元测试 10 AOP开发实例 12 综合实例----光盘资料管理系统 13 综合实例----网上书店管理应用系统 14 综合实例----餐费管理系统

    ejb3-junit-arguillian-example:单元测试 ejb3 CDI Web 应用程序

    它是一个示例、可部署的 Maven 3 项目,可帮助您在 JBoss Enterprise Application Platform 6 或 JBoss AS 7 上使用 Java EE 6 进行开发,并使用 Arquillian 进行 junit 测试。 该项目设置为允许您使用 JSF 2.0、...

    custom-maven-archetypes:Java EE和Jakarta EE项目引导的Maven原型

    该原型包含以下文件/依赖项: Jakarta EE 8 API依赖性Microprofile 3.3依赖性Mockito和JUnit 5依赖关系可进行有效测试具有bean-discovery-mode="all" beans.xml persistence.xml配置用于JTA持久单元microprofile-...

    javaee7-samples:Java EE 7示例

    该工作空间由Java EE 7示例和单元测试组成。 它们分类在不同的目录中,每个目录用于每个Technology / JSR。 有些样品/测试有说明文件,否则请阅读代码。 手册引用了其中的大多数示例,并提供了说明。 随时添加文档...

    javaee8-samples:Java EE 8示例

    该工作空间由Java EE 8示例和单元测试组成。 它们分类在不同的目录中,每个目录用于每个Technology / JSR。 有些样品/测试有说明文件,否则请阅读代码。 怎么跑? 使用Arquillian在Payara,GlassFish和Tomcat上...

    精通Spring(书签版)

    JDBC集成,事务集成,单元和集成测试。Hibernate集成,Java持久化API集成  深入讲解Java EE服务及技术集成。包括JNDI集成,EJB3.0集成.线程池和任务调度集成。Java消息服务集成,Java Mail集成,远程服务集成。Java...

    精通Spring(书签)

    JDBC集成,事务集成,单元和集成测试。Hibernate集成,Java持久化API集成  深入讲解Java EE服务及技术集成。包括JNDI集成,EJB3.0集成.线程池和任务调度集成。Java消息服务集成,Java Mail集成,远程服务集成。Java...

    精通Spring (书签版)

    JDBC集成,事务集成,单元和集成测试。Hibernate集成,Java持久化API集成  深入讲解Java EE服务及技术集成。包括JNDI集成,EJB3.0集成.线程池和任务调度集成。Java消息服务集成,Java Mail集成,远程服务集成。Java...

    Java开源企业考勤系统ClockSimpleJEE4预发布版0.9.0

    clock_test是用于单元测试的JUnit套件的测试空库。 请启动测试套件,享受104个测试方法编制的绵密的测试网。 doc下另有所有版本的release note bug报告jerry_shen_sjf@qq.com 用如下管理员登录 用户名:160208 密码...

    毕业设计.zip 在进行Java毕业设计时,可以选择与自己感兴趣的领域相关的项目,如Web应用、移动应用、数据分析等

    需求分析:在开始项目之前,需要进行充分的需求分析,明确项目的功能要求、技术要求和约束条件。...可以采用单元测试、集成测试和验收测试等不同层次的测试方法。 文档撰写:在完成项目开发后,还需要撰写相关的文档

    【JTharness4_4_0】【源代码】

    JT Harness是Sun提供的开源自动化测试框架,它提供了灵活、强大的测试管理功能,尤其适合大多数类型的单元测试,支持JUnit和自定义的测试脚本格式,支持远程测试、分布式测试。 JT Harness最初用于TCK(Technology ...

    【JTharness4_4_0】【BIN文件】

    JT Harness是Sun提供的开源自动化测试框架,它提供了灵活、强大的测试管理功能,尤其适合大多数类型的单元测试,支持JUnit和自定义的测试脚本格式,支持远程测试、分布式测试。 JT Harness最初用于TCK(Technology ...

    hangman:用Java编写的hang子手游戏

    test/ee/ -单元测试 test/uitest/测试 webapp -Web应用程序资源 技术 Web框架Struts 2 单元测试JUnit UI测试Selenide 数据库H2 (内存数据库,在测试中特别有用) 数据库迁移LiquiBase 依赖注入Guice 谢谢 非常...

Global site tag (gtag.js) - Google Analytics