Mockito alay nesnesine bir dahaki sefere çağrıldığında farklı bir şey döndürmesini nasıl söyleyebilirim?


203

Yani, sınıf düzeyinde böyle bir statik değişken olarak bir sahte nesne oluşturuyorum ... Bir testte, Foo.someMethod()belirli bir değeri döndürmek istiyorum , başka bir testte, farklı bir değer döndürmek istiyorum. Yaşadığım sorun, bu düzgün çalışması için alay yeniden oluşturmak gerekir gibi görünüyor. Alayları yeniden inşa etmekten kaçınmak ve her testte aynı nesneleri kullanmak istiyorum.

class TestClass {

    private static Foo mockFoo;

    @BeforeClass
    public static void setUp() {
        mockFoo = mock(Foo.class);
    }

    @Test
    public void test1() {
        when(mockFoo.someMethod()).thenReturn(0);

        TestObject testObj = new TestObject(mockFoo);

        testObj.bar(); // calls mockFoo.someMethod(), receiving 0 as the value

    }

    @Test
    public void test2() {
        when(mockFoo.someMethod()).thenReturn(1);

        TestObject testObj = new TestObject(mockFoo);

        testObj.bar(); // calls mockFoo.someMethod(), STILL receiving 0 as the value, instead of expected 1.

    }

}

İkinci test, testObj.bar () çağrıldığında hala değer olarak 0 alıyorum ... Bunu çözmek için en iyi yolu nedir? FooHer testte farklı bir taklit kullanabileceğimi biliyorum , ancak, birden fazla isteği mockFoozincirlemem gerekiyor, yani her testte zincirleme yapmak zorunda kalacağım.

Yanıtlar:


43

Her şeyden önce sahte statik yapmayın. Özel bir alan yapın. Sadece setUp sınıfınızı @Beforenot alanına koyun @BeforeClass. Bir demet olabilir, ama ucuz.

İkincisi, şu anda sahip olduğunuz yol, teste bağlı olarak farklı bir şey döndürmek için bir sahte almanın doğru yoludur.


441

Ayrıca Ardışık Aramalar da yapabilirsiniz (2.8.9 api'de 10 numara). Bu durumda, birden fazla thenReturn çağrısı veya birden çok parametreli (varargs) bir oneReturn çağrısı kullanırsınız.

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;

public class TestClass {

    private Foo mockFoo;

    @Before
    public void setup() {
        setupFoo();
    }

    @Test
    public void testFoo() {
        TestObject testObj = new TestObject(mockFoo);

        assertEquals(0, testObj.bar());
        assertEquals(1, testObj.bar());
        assertEquals(-1, testObj.bar());
        assertEquals(-1, testObj.bar());
    }

    private void setupFoo() {
        mockFoo = mock(Foo.class);

        when(mockFoo.someMethod())
            .thenReturn(0)
            .thenReturn(1)
            .thenReturn(-1); //any subsequent call will return -1

        // Or a bit shorter with varargs:
        when(mockFoo.someMethod())
            .thenReturn(0, 1, -1); //any subsequent call will return -1
    }
}

171
Ben de .thenReturn () varargs alır gerçeğinden yararlanabilirsiniz düşünüyorum, böylece kodu kısaltılabilir: zaman (mockFoo.someMethod ()). ThenReturn (0, 1, -1);
Justin Muller

10
@JustinMuller - bu ayrı bir cevaba değer, bence (bir yoruma karşılık olarak)
Brian Agnew

16
Bu cevap, bu durumda yapılacak doğru şey değildir. Eğer 0 ve 1 dönmek için bu yöntemi saplama, o kadar uzun çalıştırmak olarak iyi olacak test1ve daha sonra test2. Ancak sürekli entegrasyon ortamınız testleri diğer sırada gerçekleştirebilir. Ya da önce koşmadan test2kendi başına koşmak isteyebilirsin test1, bu durumda başarısız olur. Birim testleri her zaman birbirinden bağımsız olmalıdır ; ve hiçbir zaman bireysel testler arasında veya belirli bir test sırasına bağımlılık olmamalıdır . Oysa zincirleme thenReturnifadeler ...
Dawood ibn Kareem

4
... kullanımları vardır, tek bir varargs kullanmak gibi, thenReturnbu özel durumda doğru bir çözüm değildir. Bana öyle geliyor ki, buradaki yükseliş orduları soruyu anlayamadılar.
Dawood ibn Kareem

2
Junit kendisi olmadan test siparişi vermez@FixMethodOrder
Roger

29

Bir şey döndürmek için arama yapan herkes için ve sonra başka bir çağrı atma istisnası için:

    when(mockFoo.someMethod())
            .thenReturn(obj1)
            .thenReturn(obj2)
            .thenThrow(new RuntimeException("Fail"));

veya

    when(mockFoo.someMethod())
            .thenReturn(obj1, obj2)
            .thenThrow(new RuntimeException("Fail"));


14

When () yöntemi yerine spy () ve doReturn () yöntemini kullanan herkes için :

farklı çağrılarda farklı bir nesne döndürmek için ihtiyacınız olan şey şudur:

doReturn(obj1).doReturn(obj2).when(this.spyFoo).someMethod();

.

Klasik taklitler için:

when(this.mockFoo.someMethod()).thenReturn(obj1, obj2);

veya bir istisna dışında:

when(mockFoo.someMethod())
        .thenReturn(obj1)
        .thenThrow(new IllegalArgumentException())
        .thenReturn(obj2, obj3);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.