2010-10-13 27 views
13

Tôi muốn dọn dẹp cơ sở dữ liệu sau mỗi trường hợp kiểm tra mà không cần quay lại giao dịch. Tôi đã thử số DatabaseOperation.DELETE_ALL của DBUnit, nhưng nó không hoạt động nếu việc xóa vi phạm ràng buộc khoá ngoại. Tôi biết rằng tôi có thể vô hiệu hóa kiểm tra khóa nước ngoài, nhưng điều đó cũng sẽ vô hiệu hóa các kiểm tra cho các bài kiểm tra (mà tôi muốn ngăn chặn).JPA - Cách cắt bớt các bảng giữa các bài kiểm tra đơn vị

Tôi đang sử dụng JUnit 4, JPA 2.0 (Eclipselink) và cơ sở dữ liệu trong bộ nhớ của Derby. Bất kỳ ý tưởng?

Cảm ơn, Theo

+0

Tại sao bạn cần dọn sạch cơ sở dữ liệu sau mỗi lần kiểm tra? –

+4

Để tránh các tác dụng phụ. Tôi muốn mọi thử nghiệm chạy tách biệt với nhau. – Theo

Trả lời

5

Đơn giản: Trước mỗi lần kiểm tra, bắt đầu giao dịch mới và sau khi thử nghiệm, hãy cuộn lại.Điều đó sẽ cung cấp cho bạn cùng một cơ sở dữ liệu mà bạn đã có trước đây.

Đảm bảo rằng các thử nghiệm không tạo giao dịch mới; thay vì sử dụng lại cái hiện có.

+1

Vâng, nhưng theo cách đó, bạn không thể nắm bắt bất kỳ lỗi nào xảy ra trong quá trình giao dịch (ví dụ: nếu bạn kiểm tra các mối quan hệ, v.v.). – Theo

+2

Cam kết chỉ đóng giao dịch và làm cho dữ liệu trong DB vĩnh viễn. Nếu bạn có lỗi FK, bạn sẽ nhận được các lỗi đó khi bạn * tuôn ra * phiên. Không cần cam kết. –

+0

OK, điều đó có nghĩa là lệnh xóa có cùng tác dụng như cam kết, ngoại trừ việc các giao dịch được đóng và dữ liệu được thực hiện vĩnh viễn tại DB. Sẽ thử nó. Cảm ơn – Theo

1

Tôi là một chút bối rối như DBUnit sẽ khởi tạo lại cơ sở dữ liệu đến một trạng thái đã biết trước mỗi bài kiểm tra.

Chúng cũng recommend as a best practice không được dọn dẹp hoặc thay đổi dữ liệu sau khi thử nghiệm.

Vì vậy, nếu đó là dọn dẹp, bạn sẽ chuẩn bị cho bài kiểm tra tiếp theo, tôi sẽ không bận tâm.

+0

Thực ra, tôi không sử dụng DBUnit. Tôi vừa thử thao tác DELETE_ALL đã đề cập. Tôi đang điền vào cơ sở dữ liệu của tôi trong một phương thức JUnit @Before. DBUnit có hoàn toàn phù hợp với JPA không? – Theo

+0

Tôi sử dụng Unitils là một rapper xung quanh dbunit. Bạn tạo một tập dữ liệu với những thứ bạn quan tâm (trong xml: không ai là hoàn hảo), thêm một vài chú thích vào lớp kiểm tra của bạn và bạn đã hoàn thành. Xem: http://www.unitils.org/tutorial.html#Testing_with_JPA –

2

Có, kiểm tra trong giao dịch sẽ làm cho cuộc sống của bạn dễ dàng hơn nhiều, nhưng nếu giao dịch là điều của bạn thì bạn cần phải thực hiện (các) giao dịch bù trừ trong quá trình dọn dẹp (trong @After). Nghe có vẻ mất thời gian và bạn có thể kết thúc với một tập hợp các phương thức trợ giúp (trong các bài kiểm tra) để bù trừ (làm sạch) dữ liệu được tích luỹ trong thời gian @Before và các bài kiểm tra (sử dụng JPA hoặc JDBC thẳng - bất kỳ điều gì có ý nghĩa).

Ví dụ, nếu bạn sử dụng JPA và gọi tạo ra phương pháp trên các đối tượng trong các bài kiểm tra bạn có thể sử dụng (sử dụng AOP nếu bạn ưa thích hay chỉ là phương pháp thử nghiệm helper như chúng tôi) một mô hình trên tất cả các xét nghiệm để:

  1. theo dõi id của tất cả các đối tượng đã được tạo ra trong quá trình thử
  2. tích lũy chúng theo thứ tự tạo
  3. phát lại thực thể xóa cho các đơn vị theo thứ tự ngược trong @After
+0

Cách tiếp cận này có vẻ tốt, nhưng vẫn còn quá nhiều công việc cho khẩu vị của tôi. Ngay cả khi bạn theo dõi các thực thể được tạo ra, mọi thứ có thể sai nếu bạn xóa chúng theo thứ tự sai (do các vấn đề toàn vẹn tham chiếu). – Theo

+0

Có, nó quá phức tạp đối với các phòng thử nghiệm nhỏ hơn. Để ngăn chặn các thực thể sự cố RI bị xóa theo thứ tự đảo ngược để được tạo. Lợi ích chính là sau khi điều này được thực hiện, kiểm tra dọn dẹp trở nên trong suốt và đặt không phí trên các nhà phát triển. Càng thử nhiều thì càng có ý nghĩa. Một lợi ích khác: tất cả các nhà phát triển đều sử dụng cùng một khung công tác để tạo dữ liệu thử nghiệm - nếu không thì các thử nghiệm của họ sẽ không hoạt động hoặc sẽ phá vỡ điều gì đó. – topchef

0

Thiết lập của tôi khá giống: đó là Derby (nhúng) + OpenJPA 1.2.2 + DBUnit. Đây là cách tôi xử lý kiểm tra tích hợp cho nhiệm vụ hiện tại của tôi: trong mọi phương pháp @Before tôi chạy 3 kịch bản:

  1. Drop DB — một kịch bản SQL mà giọt tất cả các bảng.
  2. Tạo DB — một tập lệnh SQL để tạo lại chúng.
  3. Tập lệnh XML đơn vị DB thử nghiệm cụ thể để điền dữ liệu.

Cơ sở dữ liệu của tôi chỉ có 12 bảng và bộ dữ liệu thử nghiệm không quá lớn, hoặc — khoảng 50 bản ghi. Mỗi tập lệnh mất khoảng 500 ms để chạy và tôi duy trì chúng theo cách thủ công khi bảng được thêm hoặc sửa đổi.

Cách tiếp cận này có lẽ không được khuyến khích để thử nghiệm cơ sở dữ liệu lớn, và có lẽ nó thậm chí không thể được coi là thực hành tốt cho những cơ sở dữ liệu nhỏ; tuy nhiên, nó có một lợi thế quan trọng khi quay trở lại giao dịch theo phương thức @After: bạn thực sự có thể phát hiện những gì xảy ra tại cam kết (như các thực thể tách rời hoặc các ngoại lệ khóa lạc quan).

+0

Cảm ơn bạn, cảm ơn câu trả lời của bạn. Như bạn đã nói, cách tiếp cận này không phải là rất duy trì. Tôi muốn tránh bất kỳ tập lệnh bên ngoài nào. – Theo

18

Cách đơn giản nhất để thực hiện việc này có thể là sử dụng phương pháp jpa gốc.

@After 
public void cleanup() { 
    EntityManager em = entityManagerFactory.createEntityManager(); 
    em.getTransaction().begin(); 
    em.createNativeQuery("truncate table person").executeUpdate(); 
    em.createNativeQuery("truncate table preferences").executeUpdate(); 
    em.getTransaction().commit(); 
} 
+0

'cắt ngắn' là tuyên bố DDL và không cần phải bắt đầu giao dịch, tất cả DDL được tự động chuyển. – gadon

+3

Tôi đã đồng ý nhưng createNativeQuery yêu cầu một giao dịch. Nếu không nó đã ném một ngoại lệ. Ít nhất đó là trường hợp trong ngủ đông. –

+0

@gadon: Điều đó phụ thuộc vào cơ sở dữ liệu. Ít nhất PostgreSQL, DB2 và Informix có (một số) hỗ trợ cho DDL giao dịch. Oracle, tuy nhiên, không. – sleske

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