Mockito. Verifikasi argumen metode

220

Saya sudah mencari di Google tentang hal ini, tetapi tidak menemukan yang relevan. Saya punya sesuatu seperti ini:

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();

Sekarang, saya ingin memverifikasi itu mymethod(Object o) , yang disebut di dalam runtestmethod(), dipanggil dengan Object o, bukan yang lain. Tapi saya selalu lulus tes, apa pun yang saya masukkan verifikasi, misalnya, dengan:

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

atau

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

atau

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

Saya selalu lulus ujian. Bagaimana saya bisa menyelesaikan verifikasi itu (jika mungkin)?

Terima kasih.

manolowar
sumber

Jawaban:

334

Alternatif untuk ArgumentMatcheradalah ArgumentCaptor.

Contoh resmi:

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

Seorang penculik juga dapat didefinisikan menggunakan anotasi @Captor :

@Captor ArgumentCaptor<Person> captor;
//... MockitoAnnotations.initMocks(this);
@Test public void test() {
    //...
    verify(mock).doSomething(captor.capture());
    assertEquals("John", captor.getValue().getName());
}
eugene82
sumber
1
Terima kasih untuk sampel! Tidak pernah menggunakannya. Terasa agak aneh memiliki hal-hal seperti penculik dalam kode, tetapi itu membantu.
Artemis
1
Haha, saya tidak mengerti pertanyaannya, tetapi jawabannya sangat membantu saya. Terima kasih :-)
Marcus K.
13
Penting: Hubungi verifikasi () / tangkap () setelah menggunakan tiruan. Saya berpikir itu harus "dipasang" sebelum ...
Daniel Alder
1
Terima kasih atas jawaban ini!
Jose Flavio Quispe Irrazábal
Ini jawaban yang bagus !! Terima kasih banyak!
Ulky Igor
61

Apakah Anda mencoba melakukan kesetaraan logis menggunakan metode .equals objek? Anda dapat melakukan ini dengan menggunakan pencocokan argThat yang termasuk dalam Mockito

import static org.mockito.Matchers.argThat

Selanjutnya Anda dapat mengimplementasikan pencocokan argumen Anda sendiri yang akan tunduk pada setiap metode .equals objek

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);
    }
}

Sekarang menggunakan kode Anda, Anda dapat memperbaruinya untuk membaca ...

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)));

Jika Anda hanya akan untuk kesetaraan EXACT (objek yang sama dalam memori), lakukan saja

verify(mock).mymethod(obj);

Ini akan memverifikasi itu dipanggil sekali.

Matthew Kirkley
sumber
1
Anda bisa menggunakan build di ReflectionEqualskelas untuk keperluan itu.
takacsot
2
+1 untuk jawaban Anda. Tapi saya ingin menambahkan bahwa verify(mock).mymethod(obj);tidak memeriksa kesetaraan EXACT (objek yang sama dalam memori). Sebaliknya ia menggunakan objek sama dengan-metode yang bisa ditimpa.
efux
Anda juga dapat membuat implementasi anonim ArgumentMatcheragar tidak terlalu bertele-tele.
botchniaque
1
Lebih detail: secara default verify()memanggil metode / inbound argumen / equals(), daripada / obyek / equals()metode yang direkam . ini tidak relevan kecuali Anda mencoba untuk mengkonfirmasi bahwa subjek pengujian Anda mengembalikan instance objek tertentu, dan subjek mengembalikan apa yang seharusnya menjadi dekorator transparan dari instance itu. The verifyargumen equals()tidak akan tahu dari dekorator; sedangkan dekorator equals()akan ditulis ulang untuk mentolerir aslinya. Dalam hal ini pengujian Anda akan gagal.
Mark McKenna
54
  • Anda tidak perlu eqkorek api jika Anda tidak menggunakan korek api lainnya.
  • Anda tidak menggunakan sintaks yang benar - panggilan metode Anda harus di luar .verify(mock). Anda sekarang melakukan verifikasi pada hasil pemanggilan metode, tanpa memverifikasi apa pun (tidak melakukan pemanggilan metode). Karenanya semua tes lulus.

Kode Anda harus seperti:

Mockito.verify(mock).mymethod(obj);
Mockito.verify(mock).mymethod(null);
Mockito.verify(mock).mymethod("something_else");
Bozho
sumber
Saya sudah mencobanya sebelumnya, dan lagi sekarang untuk memastikan. Saya masih memiliki masalah yang sama, tes selalu berlalu.
manolowar
2
Itu verifeis dengan referensi
cnexans
17

argThat plus lambda

itulah cara Anda dapat gagal verifikasi argumen Anda:

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

dimana

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

argThat plus menegaskan

tes di atas akan "mengatakan" Expected: lambda$... Was: YourClass.toSting.... Anda bisa mendapatkan penyebab kegagalan yang lebih spesifik jika menggunakan penegasan dalam lambda:

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

TAPI: HANYA INI BEKERJA DENGAN 1 METODE PANGGILAN. Jika metode terverifikasi disebut 2+ kali, mockito meneruskan semua kombinasi yang dipanggil ke setiap verifier. Jadi mockito mengharapkan verifikasi Anda secara diam-diam kembali trueuntuk salah satu set argumen, dan false(tanpa pengecualian) untuk panggilan yang valid lainnya. Harapan itu bukan masalah untuk 1 panggilan metode - itu hanya harus mengembalikan true 1 kali.

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

Sekarang tes mengatakan: Expected: Obj.description to contain 'KEY'. Was: 'Actual description'. CATATAN: Saya menggunakan assertJpenegasan, tetapi terserah Anda kerangka pernyataan mana yang harus digunakan.


argThat dengan banyak argumen.

Jika Anda menggunakan argThat, semua argumen harus dilengkapi dengan kecocokan. Misalnya:

    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.

dimana:

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

eq korek api

cara termudah untuk memeriksa apakah argumennya sama:

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

argumen langsung

jika perbandingan dengan ref dapat diterima, maka lanjutkan dengan:

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

AKAR PENYEBAB kegagalan pertanyaan awal adalah tempat yang salah dari paranthes: verify(mock.mymethod.... Itu salah. Yang benar adalah:verify(mock).*

epox
sumber
1
Ini adalah jawaban favorit saya, bekerja & jauh lebih elegan daripada yang lain.
Airwavezx
11

Saya telah menggunakan Mockito.verifikasikan dengan cara ini

@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
    }
}
Bebas Pikiran
sumber
5

Sudahkah Anda memeriksa metode yang sama dengan kelas mockable? Jika yang ini mengembalikan selalu benar atau Anda menguji contoh yang sama terhadap contoh yang sama dan metode yang sama tidak ditimpa (dan karenanya hanya memeriksa terhadap referensi), maka itu mengembalikan benar.

rit
sumber
4

Metode lainnya adalah dengan menggunakan metode org.mockito.internal.matchers.Equals.Equals alih-alih mendefinisikan ulang satu:

verify(myMock).myMethod((inputObject)Mockito.argThat(new Equals(inputObjectWanted)));
Nils Renaud
sumber
3

Sudahkah Anda mencobanya dengan pencocokan () yang sama? Seperti dalam:

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

Saya memiliki masalah yang sama. Saya mencobanya dengan matcher eq () serta matcher refEq () tapi saya selalu memiliki false positive. Ketika saya menggunakan pencocokan yang sama (), tes gagal ketika argumen adalah contoh yang berbeda dan lulus begitu argumen adalah contoh yang sama.

cbbcloud
sumber
-1

Anda juga dapat menggunakan TypeSafeDiagnosingMatcher

    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());
        }
    };
}

Kemudian verifikasi permohonan itu:

Mockito.verify(client).getPackages(Mockito.argThat(expectedPackageRequest(request)));
sendon1982
sumber