Mockito. Xác minh đối số phương thức


220

Tôi đã googled về điều này, nhưng không tìm thấy bất cứ điều gì có liên quan. Tôi đã có một cái gì đó như thế này:

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj )).thenReturn(null);

Testeable testableObj = new Testeable();
testableObj.setMockeable(mock);
command.runtestmethod();

Bây giờ, tôi muốn xác minh rằng mymethod(Object o), cái được gọi bên trong runtestmethod(), được gọi bằng Object ochứ không phải cái nào khác. Nhưng tôi luôn vượt qua bài kiểm tra, bất cứ điều gì tôi đưa vào xác minh, ví dụ, với:

Mockito.verify(mock.mymethod(Mockito.eq(obj)));

hoặc là

Mockito.verify(mock.mymethod(Mockito.eq(null)));

hoặc là

Mockito.verify(mock.mymethod(Mockito.eq("something_else")));

Tôi luôn vượt qua bài kiểm tra. Làm thế nào tôi có thể thực hiện xác minh đó (nếu có thể)?

Cảm ơn bạn.

Câu trả lời:


334

Một thay thế cho ArgumentMatcherArgumentCaptor.

Ví dụ chính thức:

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());

Một captor cũng có thể được xác định bằng cách sử dụng chú thích @Captor :

@Captor ArgumentCaptor<Person> captor;
//... MockitoAnnotations.initMocks(this);
@Test public void test() {
    //...
    verify(mock).doSomething(captor.capture());
    assertEquals("John", captor.getValue().getName());
}

1
Cảm ơn mẫu! Không bao giờ sử dụng nó. Cảm thấy hơi kỳ lạ khi có những thứ như captor trong mã, nhưng nó đã giúp.
Artemis

1
Haha, tôi không hiểu câu hỏi, nhưng câu trả lời đã giúp tôi rất nhiều. Cảm ơn :-)
Marcus K.

13
Quan trọng: Gọi xác minh () / chụp () sau khi sử dụng giả. Tôi đã nghĩ rằng nó phải được "cài đặt" trước khi ...
Daniel Alder

1
Cảm ơn câu trả lời này!
Jose Flavio Quispe Irrazábal

Đây là một câu trả lời tuyệt vời !! Cảm ơn rât nhiều!
Ulky Igor

61

Bạn đang cố gắng thực hiện công bằng logic bằng cách sử dụng phương thức .equals của đối tượng? Bạn có thể làm điều này bằng cách sử dụng trình so khớp argThat có trong Mockito

import static org.mockito.Matchers.argThat

Tiếp theo, bạn có thể triển khai trình so khớp đối số của riêng mình sẽ trì hoãn cho từng đối tượng. Phương thức

private class ObjectEqualityArgumentMatcher<T> extends ArgumentMatcher<T> {
    T thisObject;

    public ObjectEqualityArgumentMatcher(T thisObject) {
        this.thisObject = thisObject;
    }

    @Override
    public boolean matches(Object argument) {
        return thisObject.equals(argument);
    }
}

Bây giờ sử dụng mã của bạn, bạn có thể cập nhật nó để đọc ...

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj)).thenReturn(null);

Testeable obj = new Testeable();
obj.setMockeable(mock);
command.runtestmethod();

verify(mock).mymethod(argThat(new ObjectEqualityArgumentMatcher<Object>(obj)));

Nếu bạn chỉ muốn bình đẳng CHÍNH XÁC (cùng một đối tượng trong bộ nhớ), chỉ cần làm

verify(mock).mymethod(obj);

Điều này sẽ xác minh nó đã được gọi một lần.


1
Bạn có thể sử dụng bản dựng trong ReflectionEqualslớp cho mục đích đó.
takacsot

2
+1 cho câu trả lời của bạn. Nhưng tôi muốn thêm rằng verify(mock).mymethod(obj);không kiểm tra sự bình đẳng CHÍNH XÁC (cùng một đối tượng trong bộ nhớ). Thay vào đó, nó sử dụng các đối tượng bằng phương thức có thể đã bị ghi đè.
efux

Bạn cũng có thể tạo một triển khai ẩn danh ArgumentMatcherđể ít dài dòng hơn.
botchniaque

1
Chi tiết hơn: theo mặc định verify()gọi equals()phương thức / đối số trong nước , thay vì phương thức / đối tượng được ghi equals(). điều này không liên quan trừ khi bạn đang cố gắng xác nhận rằng đối tượng thử nghiệm của bạn trả về một thể hiện đối tượng cụ thể và đối tượng trả về cái được cho là trang trí trong suốt của thể hiện đó. Đối verifysố equals()sẽ không biết về trang trí; trong khi trang trí equals()sẽ được viết lại để dung nạp bản gốc. Trong trường hợp này, bài kiểm tra của bạn sẽ thất bại.
Đánh dấu McKenna

54
  • Bạn không cần đến công cụ đối sánh eqnếu bạn không sử dụng các công cụ đối sánh khác.
  • Bạn không sử dụng đúng cú pháp - cuộc gọi phương thức của bạn phải nằm ngoài .verify(mock). Bây giờ bạn đang bắt đầu xác minh kết quả của cuộc gọi phương thức, mà không cần xác minh bất cứ điều gì (không thực hiện cuộc gọi phương thức). Do đó tất cả các bài kiểm tra đang qua.

Mã của bạn sẽ giống như:

Mockito.verify(mock).mymethod(obj);
Mockito.verify(mock).mymethod(null);
Mockito.verify(mock).mymethod("something_else");

Tôi đã thử điều đó trước đây và một lần nữa bây giờ để chắc chắn. Tôi vẫn có cùng một vấn đề, bài kiểm tra luôn vượt qua.
manolowar

2
Nó verifeis bằng cách tham khảo
cnexans

17

argThat cộng với lambda

đó là cách bạn có thể không xác minh đối số của mình:

    verify(mock).mymethod(argThat(
      (x)->false
    ));

Ở đâu

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

argThat cộng với khẳng định

bài kiểm tra trên sẽ "nói" Expected: lambda$... Was: YourClass.toSting.... Bạn có thể nhận được một nguyên nhân cụ thể hơn của sự thất bại nếu sử dụng các xác nhận trong lambda:

    verify(mock).mymethod(argThat( x -> {
      assertThat(x).isNotNull();
      assertThat(x.description).contains("KEY");
      return true;
    }));

NHƯNG: CHỈ CÓ CÔNG TRÌNH NÀY VỚI 1 PHƯƠNG PHÁP GỌI. Nếu phương thức được xác minh được gọi là hơn 2 lần, mockito sẽ chuyển tất cả các kết hợp được gọi cho mỗi trình xác minh. Vì vậy, mockito mong đợi trình xác minh của bạn âm thầm trả về truemột trong các đối số được đặt và false(không có ngoại lệ khẳng định) cho các cuộc gọi hợp lệ khác. Sự mong đợi đó không phải là vấn đề đối với 1 cuộc gọi phương thức - nó sẽ chỉ trả về đúng 1 lần.

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

Bây giờ kiểm tra nói : Expected: Obj.description to contain 'KEY'. Was: 'Actual description'. LƯU Ý: Tôi đã sử dụng các assertJxác nhận, nhưng tùy thuộc vào bạn sử dụng khung xác nhận nào.


argThat với nhiều đối số.

Nếu bạn sử dụng argThat, tất cả các đối số phải được cung cấp với kết quả khớp. Ví dụ:

    verify(mock).mymethod(eq("VALUE_1"), argThat((x)->false));
    // above is correct as eq() is also an argument matcher.

verify(mock).mymethod("VALUE_1", argThat((x)->false));

// above is incorrect; an exceptoin will be thrown, as the fist arg. is given without an argument matcher.

Ở đâu:

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;

eq diêm

cách dễ nhất để kiểm tra xem đối số có bằng nhau không:

verify(mock).mymethod(eq(expectedValue));
// NOTE:   ^ where the parentheses must be closed.

tranh luận trực tiếp

nếu so sánh bằng ref là chấp nhận được, thì hãy tiếp tục với:

verify(mock).mymethod(expectedArg);
// NOTE:   ^ where the parentheses must be closed.

NGUYÊN NHÂN ROOT của thất bại câu hỏi ban đầu là vị trí sai của câu hỏi : verify(mock.mymethod.... Điều đó không đúng. Quyền sẽ là:verify(mock).*


1
Đây là câu trả lời yêu thích của tôi, hoạt động và thanh lịch hơn nhiều so với những người khác.
Airwavezx

11

Tôi đã sử dụng Mockito.verify theo cách này

@UnitTest
public class JUnitServiceTest
{
    @Mock
    private MyCustomService myCustomService;


    @Test
    public void testVerifyMethod()
    {
       Mockito.verify(myCustomService, Mockito.never()).mymethod(parameters); // method will never call (an alternative can be pick to use times(0))
       Mockito.verify(myCustomService, Mockito.times(2)).mymethod(parameters); // method will call for 2 times
       Mockito.verify(myCustomService, Mockito.atLeastOnce()).mymethod(parameters); // method will call atleast 1 time
       Mockito.verify(myCustomService, Mockito.atLeast(2)).mymethod(parameters); // method will call atleast 2 times
       Mockito.verify(myCustomService, Mockito.atMost(3)).mymethod(parameters); // method will call at most 3 times
       Mockito.verify(myCustomService, Mockito.only()).mymethod(parameters); //   no other method called except this
    }
}

5

Bạn đã kiểm tra phương thức bằng cho lớp có thể giả được chưa? Nếu cái này trả về luôn luôn đúng hoặc bạn kiểm tra cùng một thể hiện với cùng một thể hiện và phương thức bằng nhau không bị ghi đè (và chỉ kiểm tra đối với các tham chiếu), thì nó trả về true.


4

Phương pháp khác là sử dụng phương thức org.mockito.iternal.matchers.Equals.Equals thay vì xác định lại:

verify(myMock).myMethod((inputObject)Mockito.argThat(new Equals(inputObjectWanted)));

3

Bạn đã thử nó với cùng () chưa? Như trong:

verify(mockObj).someMethod(same(specificInstance));

Tôi đã từng gặp vấn đề tương tự. Tôi đã thử nó với trình so khớp eq () cũng như trình so khớp refEq () nhưng tôi luôn có kết quả dương tính giả. Khi tôi sử dụng cùng một trình so khớp (), kiểm tra thất bại khi các đối số là các thể hiện khác nhau và được thông qua một khi các đối số là cùng một thể hiện.


-1

Bạn cũng có thể sử dụng TypeSafeDiagnoseMatcher

    private Matcher<GetPackagesRequest> expectedPackageRequest(final AvailabilityRequest request) {
    return new TypeSafeDiagnosingMatcher<GetPackagesRequest>() {

        StringBuilder text = new StringBuilder(500);

        @Override
        protected boolean matchesSafely(GetPackagesRequest req, Description desc) {
            String productCode = req.getPackageIds().iterator().next().getValue();
            if (productCode.equals(request.getSupplierProductCode())) {
                text.append("ProductCode not equal! " + productCode + " , " + request.getSupplierProductCode());
                return true;
            }

            text.append(req.toString());
            return false;
        }

        @Override
        public void describeTo(Description d) {
            d.appendText(text.toString());
        }
    };
}

Sau đó xác minh lời mời đó:

Mockito.verify(client).getPackages(Mockito.argThat(expectedPackageRequest(request)));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.