2015-02-24 21 views
11

Tôi đã sử dụng Java 8 trong một vài tháng và tôi đã bắt đầu sử dụng các biểu thức Lambda, rất thuận tiện cho một số trường hợp. Tuy nhiên, tôi thường gặp một số vấn đề để kiểm tra đơn vị mã sử dụng Lambda.Mã thử nghiệm đơn vị với Java 8 Lambdas

Hãy làm ví dụ các pseudo-code sau:

private Bar bar; 

public void method(int foo){ 
    bar.useLambda(baz -> baz.setFoo(foo)); 
} 

Một cách tiếp cận sẽ được chỉ cần xác minh các cuộc gọi trên thanh

verify(bar).useLambda(Matchers.<Consumer<Baz>>.any()); 

Nhưng, bằng cách làm đó, tôi không kiểm tra Mã của Lambda.

Cũng lưu ý rằng tôi không thể thay thế Lambda với một tài liệu tham khảo phương pháp và sử dụng phương pháp:

bar.useLambda(This::setFooOnBaz); 

Bởi vì tôi sẽ không có foo trên phương pháp đó. Hoặc ít nhất đó là những gì tôi nghĩ.

Bạn có gặp vấn đề này trước đây chưa? Làm thế nào tôi có thể kiểm tra hoặc refactor mã của tôi để kiểm tra nó đúng cách?


Sửa

Từ những gì tôi đang mã hóa là một bài kiểm tra đơn vị, tôi không muốn nhanh chóng thanh, và tôi sẽ sử dụng một mô hình thay thế. Vì vậy, tôi sẽ không thể chỉ xác minh cuộc gọi baz.setFoo.

Trả lời

14

Bạn không thể đơn vị kiểm tra trực tiếp lambda vì nó không có tên. Không có cách nào để gọi nó trừ khi bạn có một tham chiếu đến nó.

Cách thay thế thông thường là cấu trúc lại lambda thành một phương thức được đặt tên và sử dụng tham chiếu phương thức từ mã sản phẩm và gọi phương thức theo tên từ mã thử nghiệm. Như bạn lưu ý, trường hợp này không thể được tái cấu trúc theo cách này bởi vì nó bắt giữ foo và điều duy nhất có thể được chụp bằng tham chiếu phương thức là người nhận.

Nhưng answer from yshavit chạm vào một điểm quan trọng về việc có cần thiết cho phương pháp riêng thử nghiệm đơn vị hay không. Một lambda chắc chắn có thể được coi là một phương pháp riêng tư.

Có một điểm lớn hơn ở đây. Một trong những nguyên tắc của thử nghiệm đơn vị là bạn không cần phải kiểm tra đơn vị bất cứ điều gì đó là too simple to break. Điều này phù hợp tốt với trường hợp lý tưởng cho lambda, đó là một biểu thức rất đơn giản, nó rõ ràng là chính xác. (Ít nhất, đó là những gì tôi xem xét lý tưởng.) Xem xét ví dụ:

baz -> baz.setFoo(foo) 

Có nghi ngờ rằng biểu thức lambda này, khi trao một tài liệu tham khảo Baz, sẽ gọi phương thức setFoo của nó và vượt qua nó foo như một cuộc tranh cãi? Có lẽ nó đơn giản đến nỗi nó không cần phải được kiểm tra đơn vị.

Mặt khác, đây chỉ là một ví dụ và có lẽ lambda thực tế bạn muốn kiểm tra phức tạp hơn nhiều. Tôi đã nhìn thấy mã sử dụng lambdas nhiều, lồng nhau, nhiều dòng. Xem ví dụ: this answer và câu hỏi của nó cũng như các câu trả lời khác. Lambdas như vậy thực sự là khó khăn để gỡ lỗi và thử nghiệm. Nếu mã trong lambda đủ phức tạp mà nó đảm bảo kiểm tra, có lẽ mã đó phải được tái cấu trúc ra khỏi lambda, để nó có thể được kiểm tra bằng cách sử dụng các kỹ thuật thông thường.

+0

Bạn đã đúng khi bạn đã nói rằng lambda thực sự của tôi phức tạp hơn một chút so với một bộ, nhưng nó vẫn đủ đơn giản để xem xét rằng nó sẽ không phá vỡ. Sau khi tất cả, có lẽ tôi chỉ cố gắng để đơn vị kiểm tra 100% mã, và đó là vấn đề gốc. Cảm ơn! – Fdiazreal

11

Hãy đối xử với lambdas như bạn sẽ là phương pháp riêng tư; không kiểm tra nó một cách riêng biệt, mà là kiểm tra hiệu quả của nó. Trong trường hợp của bạn, gọi method(foo) sẽ gây ra bar.setFoo để xảy ra - vì vậy, hãy gọi method(foo) và sau đó xác minh bar.getFoo().

+1

Đồng ý, không đơn vị kiểm tra lambda; đơn vị kiểm tra kết quả. – whitfin

+0

Làm thế nào bạn sẽ xác minh 'baz.setFoo' mà không cần thanh instantiating, do đó, sử dụng thanh như một mô hình? – Fdiazreal

+3

@Fdiazreal: khi bạn đang ủy quyền cho 'Bar', không có điểm nào trong việc thử nghiệm hành động này" không có thanh khởi tạo ". Tất nhiên, bạn có thể tự kiểm tra 'baz.setFoo (foo)'. Vì 'setFoo' là một phương thức thông thường, bạn sẽ không gặp vấn đề gì khi thử nghiệm nó - đơn giản là quên đi lambda. – Holger

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