Java EE单元测试笔记

来源:互联网 发布:网站域名和空间 编辑:程序博客网 时间:2024/05/25 21:34

1. 单元测试 

1.1  测试对象。

1) OracleResource 是一个 Enterprise JavaBeans (EJB) 3.1 bean,用(REST) 来公开他的预言。

@Path("javafuture")@Statelesspublic class OracleResource {   @Inject   Instance<Consultant> company;   @Inject   Event<Result> eventListener;   @GET   @Produces(MediaType.TEXT_PLAIN)   public String predictFutureOfJava(){     checkConsultantAvailability();     Consultant consultant = getConsultant();     Result prediction = consultant.predictFutureOfJava();     eventListener.fire(prediction);     if(JAVA_IS_DEAD.equals(prediction)){       throw new IllegalStateException("Please perform a sanity / reality check");     }     return prediction.name();   }   void checkConsultantAvailability(){     if(company.isUnsatisfied()){       throw new IllegalStateException("No consultant to ask!");     }   }   Consultant getConsultant(){     for (Consultant consultant : company) {       return consultant;     }     return null;   }}
2) Consultant 是一个 Java 接口, Blogger是一个实现。

public class Blogger implements Consultant{   @Override   public Result predictFutureOfJava() {     return Result.JAVA_IS_DEAD;   }}
3) PredictionAudit 也是EJB 3.1 bean,保存所有成功的和失败的预言。

@Statelesspublic class PredictionAudit {   @PersistenceContext  EntityManager em;   public void onSuccessfulPrediction(@Observes(during= TransactionPhase.AFTER_SUCCESS) Result result){    persistDecision(result,true);   }  public void onFailedPrediction(@Observes(during= TransactionPhase.AFTER_FAILURE) Result result){     persistDecision(result,false);   }  void persistDecision(Result result,boolean success) {     Prediction prediction = new Prediction(result,success);     em.persist(prediction);  }   public List<Prediction> allDecisions(){     return this.em.createNamedQuery(Prediction.findAll).getResultList();  }}
4)Prediction是JPA 2 实体。

@Entity@XmlRootElement@XmlAccessorType(XmlAccessType.FIELD)@NamedQuery(name=Prediction.findAll,query="Select d from Prediction d")public class Prediction { public final static String PREFIX = "com.abien.testing.oracle.entity.Prediction."; public final static String findAll = PREFIX + "findAll"; @Id @GeneratedValue @XmlTransient private long id;  @Column(name="prediction_result") @Enumerated(EnumType.STRING) private Result result;  @Temporal(TemporalType.TIME) private Date predictionDate; private boolean success; public Prediction() {   this.predictionDate = new Date(); }  public Prediction(Result result, boolean success) {    this();    this.result = result;    this.success = success; }//bookkeeping methods omitted}
1.2 单元测试。

1) 选用Mockito来“模拟”各种难以实现的类、资源或服务,原理是它能够从类或接口创建“智能代理”(也称为模拟)

2) 要精确测试 PredictionAudit 类,必须“模拟”EntityManager。之后测试 EntityManager#persist 方法是否接收正确参数,但这里我们不测试是否真正保存 Prediction 实体。

import static org.mockito.Mockito.*;public class PredictionAuditTest { private PredictionAudit cut;  @Before public void initializeDependencies(){    cut = new PredictionAudit();    cut.em = mock(EntityManager.class); }  @Test public void savingSuccessfulPrediction(){    final Result expectedResult = Result.BRIGHT;    Prediction expected = new Prediction(expectedResult, true);    this.cut.onSuccessfulPrediction(expectedResult);    verify(cut.em,times(1)).persist(expected); } @Test public void savingRolledBackPrediction(){    final Result expectedResult = Result.BRIGHT;    Prediction expected = new Prediction(expectedResult, false);    this.cut.onFailedPrediction(expectedResult);    verify(cut.em,times(1)).persist(expected); }}
3)精确测试OracleResource类,需要模拟 javax.enterprise.event.Event 和 javax.enterprise.inject.Instance。

public class OracleResourceTest { private OracleResource cut; @Before public void initializeDependencies(){    this.cut = new OracleResource();    this.cut.company = mock(Instance.class);    this.cut.eventListener = mock(Event.class); }
如果未找到 Consultant 实现,我们希望生成 IllegalStateException。
@Test(expected=IllegalStateException.class) public void checkConsultantAvailabilityWithoutConsultant(){    when(this.cut.company.isUnsatisfied()).thenReturn(true);    this.cut.checkConsultantAvailability(); }
模拟 javax.enterprise.inject.Instance 返回的 Iterator:
 Iterator mockIterator(Consultant consultant) {    Iterator iterator = mock(Iterator.class);    when(iterator.next()).thenReturn(consultant);    when(iterator.hasNext()).thenReturn(true);    return iterator; }

通过上面的Iterator,枚举到Consultant 接口的 Blogger 实现则会返回 JAVA_IS_DEAD,这将引发 IllegalStateException。

@Test(expected=IllegalStateException.class) public void unreasonablePrediction(){    Consultant consultant = new Blogger();    Iterator iterator = mockIterator(consultant);    when(this.cut.company.iterator()).thenReturn(iterator);    this.cut.predictFutureOfJava(); }
模拟 Event 实例,验证方法调用。

@Test public void unreasonablePredictionFiresEvent(){    Consultant consultant = new Blogger();    Result expectedResultToFire = consultant.predictFutureOfJava();    Iterator iterator = mockIterator(consultant);    when(this.cut.company.iterator()).thenReturn(iterator);    try{        this.cut.predictFutureOfJava();    }catch(IllegalStateException e){}    verify(this.cut.eventListener,times(1)).fire(expectedResultToFire); }
下面PredictionArchiveResource 使用了直接注入的 PredictionAudit 类。

@Path("predictions")@Statelesspublic class PredictionArchiveResource { @EJB PredictionAudit audit; @GET @Produces(MediaType.APPLICATION_JSON) public List<Prediction> allPredictions(@DefaultValue("5") @QueryParam("max") int max) {    List<Prediction> allPredictions = audit.allPredictions();    if (allPredictions.size() <= max) {        return allPredictions;    } else {        return allPredictions.subList(0, max);    } }}
尽管 PredictionAudit 是一个类而不是一个接口,但也可以轻松地模拟它。为了测试返回列表的大小限制,对 PredictionAudit 类进行了全面模拟
public class PredictionArchiveResourceTest {  PredictionArchiveResource cut;  @Before public void initialize(){    this.cut = new PredictionArchiveResource();    this.cut.audit = mock(PredictionAudit.class); } @Test public void allDecisionsWithMaxLesserReturn() throws Exception {    int expectedSize = 2;    List<Prediction> prediction = createDecisions(expectedSize);    when(this.cut.audit.allPredictions()).thenReturn(prediction);     List<Prediction> allDecisions = this.cut.allPredictions(3);    assertThat(allDecisions.size(), is(expectedSize)); } @Test public void allDecisionsWithMaxGreaterReturn() throws Exception {    int max = 5;    int expected = 3;    List<Prediction> prediction = createDecisions(max);    when(this.cut.audit.allPredictions()).thenReturn(prediction);     List<Prediction> allDecisions = this.cut.allPredictions(expected);    assertThat(allDecisions.size(), is(expected)); } @Test public void allDecisionsWithMaxEqualReturn() throws Exception { //obvious code omitted } List<Prediction> createDecisions(final int nr) {    return new ArrayList<Prediction>(){{        for (int i = 0; i < nr; i++) {           add(new Prediction(Result.BRIGHT, true));        }     }}; }}

原帖(http://www.oracle.com/technetwork/cn/articles/java/unittesting-455385-zhs.html)

原帖代码:https://kenai.com/projects/javaee-patterns/sources/hg/show/TestingEJBAndCDI





0 0
原创粉丝点击