2010-08-25 17 views
9

Trong spring documentation regarding testing, nó khẳng định:Cần giải thích về sự cần thiết của việc xả nước trước để tránh những sai lầm tích cực khi Thử nghiệm với Mùa xuân?

Tránh dương tính giả khi thử nghiệm ORM đang

Khi bạn kiểm tra mã liên quan đến một khuôn khổ ORM như JPA hay Hibernate, hãy xả nằm bên dưới phiên trong vòng thử nghiệm các phương thức mà cập nhật trạng thái của phiên. Không tuôn ra khung ORM phiên bản cơ bản của ORM có thể sản xuất sai tích cực: thử nghiệm của bạn có thể vượt qua, nhưng mã số ném ngoại lệ trong môi trường sản xuất trực tiếp . Trong các trường hợp sau Hibernate dựa trên ví dụ trường hợp, một phương pháp chứng minh một sai tích cực và các phương pháp khác một cách chính xác cho thấy kết quả của xả phiên.

Ai đó có thể giải thích lý do tại sao tôi cần phải gọi xả?

Trả lời

3

Vâng, bạn thực sự bỏ qua phần thú vị, ví dụ :) Ở đây là:

// ... 

@Autowired 
private SessionFactory sessionFactory; 

@Test // no expected exception! 
public void falsePositive() { 
    updateEntityInHibernateSession(); 
    // False positive: an exception will be thrown once the session is 
    // finally flushed (i.e., in production code) 
} 

@Test(expected = GenericJDBCException.class) 
public void updateWithSessionFlush() { 
    updateEntityInHibernateSession(); 
    // Manual flush is required to avoid false positive in test 
    sessionFactory.getCurrentSession().flush(); 
} 

// ... 

gì ví dụ này cố gắng để minh họa là trừ khi bạn thực sự flush phiên (AKA cache cấp độ đầu tiên) để đồng bộ các thay đổi trong bộ nhớ với cơ sở dữ liệu, bạn không thực sự thử nghiệm tích hợp cơ sở dữ liệu và có thể không kiểm tra hành vi mong đợi thực sự hoặc bỏ lỡ một vấn đề. Ví dụ: cơ sở dữ liệu có thể trả về lỗi do vi phạm ràng buộc và nếu bạn không nhấn vào cơ sở dữ liệu, bạn sẽ không thể hiện hành vi đúng này, như trong phương pháp kiểm tra falsePositive() ở trên. Phương pháp thử này sẽ thất bại, hoặc mong đợi một ngoại lệ nhưng sẽ chỉ vượt qua. Mặt khác, phương pháp thử nghiệm khác với tuôn ra không kiểm tra hành vi thực tế. Do đó cần phải flush.

+0

Pascal, cảm ơn. Đề nghị ở đây là gì? flush() sau khi lưu và tránh cache cấp đầu tiên khi hiệu năng không phải là vấn đề lớn? Và chúng ta có nên kêu gọi tuôn ra sau khi gọi phương thức được thử nghiệm bên ngoài cuộc gọi phương thức hoặc thậm chí bên trong không? Làm thế nào khó hiểu! – JavaRocky

1

Tài liệu mùa xuân sử dụng khái niệm sai. Nó đã được rõ ràng

nhưng cùng một mã ném một ngoại lệ trong một môi trường sản xuất trực tiếp

Ở đây đi wikipedia

sai lầm loại II, còn được gọi là lỗi" của loại thứ hai ", lỗi,, hoặc" sai âm ": lỗi không từ chối giả thuyết không đúng khi thực tế là không đúng. Một ví dụ về điều này sẽ là nếu một thử nghiệm cho thấy rằng một người phụ nữ không mang thai, trong thực tế, cô ấy là.

Nếu bạn thấy mẫu được cung cấp bởi Spring, Môi trường sản xuất ném một ngoại lệ (A GenericJDBCException), nhưng nó đã không được phát hiện. Để xem, bạn phải gọi cam kết cơ bản khi sử dụng một số nhà cung cấp ORM.

mẫu XUnit thử định nghĩa

Một situantion trong đó một thử nghiệm đi mặc dù hệ thống được kiểm tra không hoạt động đúng.

Vì vậy khái niệm đúng là falseNegative

@Test // no expected exception! 
public void falseNegative() { 
1

kiểm tra chú thích mùa xuân với @Transactional là thuận tiện nhưng nó không phải là cách mã sản xuất của bạn sẽ được thực thi. Chú thích @Transactional sẽ bắt đầu một giao dịch trước khi chạy phương thức thử nghiệm của bạn và nó sẽ cuộn nó trở lại khi phương thức thử nghiệm kết thúc.

Trong khi cam kết được đi trước bằng lệnh tuôn ra, thì việc khôi phục không được, do đó, việc xả thủ công là cơ chế an toàn để đảm bảo tất cả thay đổi thực thể được dịch sang câu lệnh SQL.

Một thiết kế thích hợp hơn sẽ được vẽ ranh giới giao dịch một cách rõ ràng như thế này:

@Test 
public void testRootObjects() { 

    final Company newCompany = new Company(); 
    newCompany.setName("TV Company"); 

    final Long companyId = transactionTemplate.execute(new TransactionCallback<Long>() { 
     @Override 
     public Long doInTransaction(TransactionStatus transactionStatus) { 
      entityManager.persist(newCompany); 
      return newCompany.getId(); 
     } 
    }); 
    Company detachedCompany = transactionTemplate.execute(new TransactionCallback<Company>() { 
     @Override 
     public Company doInTransaction(TransactionStatus transactionStatus) { 
      Company attachedCompany = entityManager.find(Company.class, companyId); 
      assertEquals(newCompany, attachedCompany); 
      assertEquals(newCompany.hashCode(), attachedCompany.hashCode()); 
      return attachedCompany; 
     } 
    }); 
    assertEquals(newCompany, detachedCompany); 
    assertEquals(newCompany.hashCode(), detachedCompany.hashCode()); 
} 

Các TransactionTemplate sẽ cam kết mã của bạn nên không cần thiết phải bừng bằng tay.

Nếu bạn gọi phương thức dịch vụ @Transactional thông qua giao diện của chúng, bạn sẽ không cần transactionTemplate chút nào, vì bạn đang gọi một proxy Spring sẽ gọi TransactionInterceptor (giả sử bạn hướng dẫn Spring nhận biết chú thích giao dịch) và do đó các giao dịch sẽ được bắt đầu/cam kết nhân danh bạn.

0

Có ai đã kiểm tra bằng chú thích @TransactionConfiguration không? Nếu bạn đang sử dụng chú thích @Transactional trong dự án của mình, bạn có thể chỉ cần đặt @TransactionConfiguration (defaultRollback = false, transactionManager = "YourTransactionManager") trong trường hợp thử nghiệm của bạn sẽ hoạt động hoàn hảo, hy vọng điều này sẽ giúp bạn.

Các vấn đề liên quan