2015-11-12

[Mokito] 使用Mokito寫測試的筆記 (Note for writing test cases by Mokito)


Test Class Template
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;

import static android.os.Build.VERSION_CODES.LOLLIPOP;

@Config(sdk = LOLLIPOP, constants = BuildConfig.class)
@RunWith(RobolectricGradleTestRunner.class)
public class MyTest {

    // something to mock
    @Mock TypeA A;
    @Spy TypeB B = new TypeB();
    // ...

    // Set up
    @Before public void setUp() throws Exception {
        initMocks(this);    // create mock objects, ex. A and B above
        // ... do so other init things
    }

    // Tear down
    @After public void tearDown() {
        // ... do so tear down things
    }

    // Test Case (which should not throw exception)
    @Test public void testCase1() throws Exception {
        // do something
    }

    // Test Case (expect exception)
    @Test(expected=YouExceptException.class) public void testException1() {
       // something would throw YouExceptException.class exception
    }

    // Test Case (expect exception)
    @Test public void testException2() throws Exception {
        try {
            // something should throw exception
            // import org.assertj.core.api.Assertions;
            Assertions.failBecauseExceptionWasNotThrown(YouExpectException.class);
        } catch (YouExpectException e) {
        }
        // verify other things here
    }

    // Test Case (with timeout)
    @Test(timeout=100) public void infinity() {
       // something should not run longer than 100ms
    }
    
}



====
Mock something (create a fake object)

1. Use @Mock to create mock member variables. (see above)
2.
MyClass mockObject = Mockito.mock(MyClass.class);

3. Mock Generic Type Class
MyClass<T> mockObject = (MyClass<T>) Mockito.mock(MyClass.class);
====
When ( tell the mock objects what to return )
// tell the object what to return when its function is called.
when(mockObject.functionA()).thenReturn(valueA);
when(mockObject.functionB()).thenReturn(valueB);

// return different values based on the input
when(mockObject.functionC(inputA)).thenReturn(valueA);
when(mockObject.functionC(inputB)).thenReturn(valueB);

// return a value based on the type of the provide parameter
// use anyInt(), anyString()...
when(mockObject.functionD(anyInt())).thenReturn(-1);
when(mockObject.functionD(isA(ThisIsAClass.class))).thenReturn(0);

// return different values if the function may be called many times
// Iterator i= mock(Iterator.class);
when(i.next()).thenReturn("first").thenReturn("second");
====
Spy something (create a real object, but fake some of its functions)
MyClass spyObject = spy(new MyClass());

//You have to use doReturn() for stubbing
doReturn("foo").when(spyObject).functionA();
====
Verify
// verify functionA is called once
verify(mockObject).functionA();

// verify functionB with parameter valueA is called once
verify(mockObject).functionB(Matchers.eq(valueB));

// verify function is called many times
verify(mockObject, times(2)).functionA();

// verify function is never called
verify(mockObject, never()).functionC();
verify(mockObject, never()).functionD(anyInt());

// other verify functions
verifyZeroInteractions(mockObject);
verify(mock, atLeastOnce()).someMethod("called at least once");
verify(mock, atLeast(2)).someMethod("called at least twice");
verify(mock, atMost(3)).someMethod("called at most 3 times");

// if one of the parameter use the matcher, all parameters have to use matcher.
// this is correct  
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));  
//  the following will throw exception  
// verify(mock).someMethod(anyInt(), anyString(), "third argument"); 
====
assertThat (check value)
(org.assertj.core.api.Assertions.assertThat)
assertThat(obj.functionA()).isFalse();
assertThat(obj.functionA()).isTrue();
assertThat(obj.functionA()).isNull();
assertThat(obj.functionA()).isNotNull();
assertThat(obj.functionA()).isEqualTo("ABC");
assertThat(obj.functionA()).isNotEqualTo("ABC");
====
Observable Testing (Using TestSubscriber)
Subscriber subscriber = spy(new TestSubscriber());

// ...

Observable observable = CreateAnObservable(); // new an Observable
observable.subscribe(subscriber);

// Something you can verify
subscribe.assertNoErrors();
verify(subscriber, times(2)).onNext(cursor);
verify(subscriber).onNext(cursor);
verify(subscriber, never()).onError(any(Throwable.class));
verify(subscriber).onCompleted();

====

1. any(String.class) 和 anyString()
any(String.class) 包含 null和任何String
anyString() 只包含任何String, 不包含Null

2. new出來的obj (不是mock出來的obj) 才有method的實作
如果要改變obj中其中的幾個method的回傳值
要先用spy()來得到spy obj
然後用doReturn(returnValue).when(...)

3. mock出來的obj 沒有method的實作
要用when(...).thenReturn(...) 來控制obj內的method會回傳什麼

4. static和final的method, class...等無法mock
如果想要測試static function
只能把static function多包一層放在某個class的non-static function內