2012-01-31 6 views
13

Tôi có một lớp học Foo là SUT và lớp học Bar, là cộng tác viên của nó. Foo gọi run(List<Object> values) trên Bar với "expectedList" làm đối số. Sau đó, Foo sẽ thêm một vài yếu tố nữa vào số List này để trạng thái của nó sẽ khác với thời điểm gọi là run(). Đây là trường hợp thử nghiệm của tôi.Mockito có thể xác minh các tham số dựa trên giá trị của chúng tại thời điểm gọi phương thức không?

@Test 
public void testFoo() { 
    Bar collaborator = spy(new Bar()); 
    Foo sut = new Foo(collaborator); 
    verify(collaborator).run(expectedList); 
} 

Lưu ý rằng cộng tác viên thực sự là đối tượng gián điệp chứ không phải là mô hình. Trường hợp kiểm tra này sẽ thất bại vì mặc dù run() được gọi với đối số bằng expectedList, nó đã được sửa đổi vì giá trị hiện tại của nó không còn bằng expectedList. Tuy nhiên, đây là cách nó được cho là hoạt động, vì vậy tôi tự hỏi liệu có cách nào để Mockito lưu trữ ảnh chụp các tham số khi phương thức được gọi và xác minh chúng dựa trên các giá trị này thay vì các giá trị gần đây nhất.

Trả lời

11

Sử dụng số Answer để kiểm tra giá trị của đối số khi phương thức được gọi. Bạn có thể ném AssertionError trong số Answer nếu giá trị sai hoặc bạn có thể lưu trữ giá trị và thực hiện xác nhận của bạn ở cuối.

+0

Vâng David đúng. Do cách API của Mockito được tạo nên nó không thể xác minh nhiều cuộc gọi với cùng tham chiếu đối số. EasyMock có thể làm điều đó bởi vì nó có một giai đoạn mong đợi trước khi mã sản xuất được chạy. Dù sao thay vì 'Trả lời' tôi sử dụng' ArgurmentCaptor' và viết một hoặc nhiều xác nhận vào trạng thái cuối cùng của danh sách đó, tức là với FEST-Assert 'assertThat (captor.getValue()). Chứa (" A "," B ") .contains (" T "," U ");' – Brice

+0

@Brice - cách thức hoạt động khác với phương pháp của Michael Wiles? –

+0

Nó không phải là. Nó chỉ là một cách khác nhau để đạt được mục đích thử nghiệm. Bởi vì hầu hết thời gian bạn không thực sự cần phải kiểm tra đối số trung gian, nhưng chỉ là một số tương tác đã xảy ra và kết quả cuối cùng.Mặc dù tôi phải nói nếu Tom có ​​yêu cầu cụ thể thì đồng ý điều này sẽ không giúp anh ta, nhưng trong trường hợp này tôi sẽ tránh các đối tượng có thể thay đổi trong mã sản xuất của tôi. Có vẻ như việc nhắn tin giữa hai cộng tác viên và tin nhắn luôn luôn là bất biến. – Brice

0

Bạn không thể gọi verify() trên một đối tượng không phải là mock. Đây có phải là ý của bạn không?

Bar collaborator = mock(Bar.class); 
Foo sut = spy(new Foo(collaborator)); 
verify(collaborator).run(expectedList); 
+0

Cảm ơn, mã ví dụ đã xảy ra lỗi và tôi đã sửa lỗi đó. Đó không phải là câu hỏi của tôi. Đó là về việc có thể xác minh một đối số dựa trên giá trị của nó tại thời điểm cuộc gọi phương thức, không phải là giá trị gần đây nhất. –

-1

Tại sao bạn không thử sử dụng chụp đối số để lấy giá trị của danh sách mong muốn khi nó được chạy và sau đó bạn có thể so sánh nó.

ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class); 

verify(collaborator).run(listCaptor.capture()); 

assertEquals(expectedList, argument.getValue()); 
+6

Nếu danh sách đã sửa đổi của bạn là cùng một cá thể, thì argument.getValue() sẽ trả về cá thể 'expectedList', không phải là một bản sao, do đó, về cơ bản giống như anh ta đang làm, phải không? – jhericks

+0

@Michael Wiles Cảm ơn, nhưng như jhericks đã đề cập, các ArgumentCaptor chụp dụ bản gốc. –

+0

Xin lỗi, Michael, tôi đã bình chọn câu trả lời của bạn vì giải pháp của bạn có cùng vấn đề với bài kiểm tra của OP, như được giải thích bởi jhericks. –

1

The answer of Dawood ibn Kareem làm việc cho tôi nhưng tôi thiếu một ví dụ, tôi cũng sử dụng Kotlin và Mockito-Kotlin, vì vậy giải pháp của tôi là như thế này:

class Foo(var mutable: String) 

interface Bar { 
    fun run(foo: Foo) 
} 

@Test fun `validate mutable parameter at invocation`() { 
    val bar = mock<Bar>() 

    var valueAtInvocation: String? = null 
    whenever(bar.run(any())).then { 
     val foo = it.arguments.first() as Foo 
     valueAtInvocation = foo.mutable // Store mutable value as it was at the invocation 
     Unit // The answer 
    } 

    val foo = Foo(mutable = "first") 
    bar.run(foo) 
    valueAtInvocation isEqualTo "first" 

    foo.mutable = "second" 
    bar.run(foo) 
    valueAtInvocation isEqualTo "second" 
} 

valueAtInvocation sẽ đại diện cho giá trị tài sản foo.mutable có thể thay đổi tại gọi cuối cùng của bar.run(foo). Cũng có thể thực hiện các xác nhận trong khối then {}.