2016年8月26日 星期五

Mockito amd Power Mock

Mocking-Mockito
Mockito allows you to stub method calls and verify interactions with objects.

When we write unit tests, we need to think of testing a certain component in isolation. We should not test anything beyond what that class’ responsibility is. Mockito helps us achieve this separation.


see:

see:

good:


1.

repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }


2.
MockitoAnnotations.initMocks(this);


3.mock and InjectMocks

mock :is the object that you want to mock,will mock all the method in the object
spy:create a onjetc,and mock only some method.
InjectMocks :the object that contain mock,no need to create a object



4.when----than run

public interface CalculatorService {
   public double add(double input1, double input2);
   public double subtract(double input1, double input2);
   public double multiply(double input1, double input2);
   public double divide(double input1, double input2);
}
public class MathApplication {
   private CalculatorService calcService;

  /* public void setCalculatorService(CalculatorService calcService){
       this.calcService = calcService;
   }*/

   public double add(double input1, double input2){
       return calcService.add(input1, input2);
//        return input1 + input2;
   }

   public double subtract(double input1, double input2){
       return calcService.subtract(input1, input2);
   }

   public double multiply(double input1, double input2){
       return calcService.multiply(input1, input2);
   }

   public double divide(double input1, double input2){
       return calcService.divide(input1, input2);
   }
}
public class PortfolioTester {


   @InjectMocks
   MathApplication matApplication;
   @Mock
   CalculatorService calculatorService;


   @Before
   public void setup() {
       MockitoAnnotations.initMocks(this);
//        matApplication = new MathApplication();
   }

   @Test
   public void testAdd() {
       when(calculatorService.add(10,20)).thenReturn(30d);
       Assert.assertEquals(30d,matApplication.add(10,20),0);
       verify(calculatorService).add(10,20);
   }




}






5.verify()
check 一個mock的action有無executr with specific 參數

6. verify,check the method execute run at pecific time
use with time ,never function

@Test
   public void testAdd() {
       matApplication.i=1;
       when(calculatorService.add(10,20)).thenReturn(30d);
       //add the behavior of calc service to subtract two numbers
       when(calculatorService.subtract(20.0,10.0)).thenReturn(10.00);
       when(calculatorService.subtract(20.0,10.0)).thenReturn(10.00);

       //test the add functionality
       Assert.assertEquals(matApplication.add(10.0, 20.0),30.0,0);
       Assert.assertEquals(matApplication.add(10.0, 20.0),30.0,0);
       Assert.assertEquals(matApplication.add(10.0, 20.0),30.0,0);

       //test the subtract functionality
       Assert.assertEquals(matApplication.subtract(20.0, 10.0),10.0,0.0);
       //default call count is 1
       verify(calculatorService).subtract(20.0, 10.0);

       //check if add function is called three times
       verify(calculatorService, times(3)).add(10.0, 20.0);

       //verify that method was never called on a mock
       verify(calculatorService, never()).multiply(10.0,20.0);
   }

7. atLeast (int min) − expects min calls.

atLeastOnce () − expects at least one call.

atMost (int max) − expects max calls.


same above

8.Exception Handling
make some Exception when some mehod run

   when(calculatorService.add(10.0,20.0)).thenReturn(30d);
       doThrow(new RuntimeException("Add operation not implemented"))
               .when(calculatorService).add(10.0,20.0);

       //test the add functionality
       Assert.assertEquals(matApplication.add(10.0, 20.0),30.0,0);


9.createn mock
Mockito provides various methods to create mock objects.
calcService = mock(CalculatorService.class);

10.ensure the oder of the method

//add the behavior to add numbers
       when(calculatorService.add(20.0, 10.0)).thenReturn(30.0);

       //subtract the behavior to subtract numbers
       when(calculatorService.subtract(20.0, 10.0)).thenReturn(10.0);

       //test the add functionality
       Assert.assertEquals(calculatorService.add(20.0, 10.0), 30.0, 0);

       //test the subtract functionality
       Assert.assertEquals(matApplication.subtract(20.0, 10.0), 10.0, 0);

       //create an inOrder verifier for a single mock
       InOrder inOrder = inOrder(calculatorService);

       //following will make sure that add is first called then subtract is called.
       inOrder.verify(calculatorService).add(20.0, 10.0);
       inOrder.verify(calculatorService).subtract(20.0, 10.0);

11.spy_use the real object to mock

when to use spy?
當有一real object ,我們想mock 他其中一些方法,就用spy

private class Calculator implements CalculatorService{
       @Override
       public double add(double input1, double input2) {
           return input1+input2;
       }

       @Override
       public double subtract(double input1, double input2) {
           throw new UnsupportedOperationException("Method not implemented yet!");
       }

       @Override
       public double multiply(double input1, double input2) {
           throw new UnsupportedOperationException("Method not implemented yet!");
       }

       @Override
       public double divide(double input1, double input2) {
           throw new UnsupportedOperationException("Method not implemented yet!");
       }
   }

@Before
   public void setup() {
       MockitoAnnotations.initMocks(this);

       mathApplication=new MathApplication();
       calc=spy(new Calculator());



       mathApplication.setCalculatorService(calc);

   }

@Test
   public void testAdd() {

       when(calc.add(10,10)).thenReturn(30d);
       doReturn(0d).when(calc).subtract(10,10);

       Assert.assertEquals(30d,mathApplication.add(10,10),0);
       Assert.assertEquals(0d,mathApplication.subtract(10,10),0);

   }

although the real method is 10+10 return 20,but we can mock it return 30

need to use doReturn because the subtract method not finish,use when will throw new UnsupportedOperationException("Method not implemented yet!");

12 reset the mock


public class PortfolioTester {

   @Mock
   CalculatorService cs;

   @InjectMocks
   private MathApplication mathApplication;


   @Before
   public void setup() {
       mathApplication = new MathApplication();
       MockitoAnnotations.initMocks(this);

   }

   @Test
   public void testAdd() {

       when(mathApplication.add(10, 10)).thenReturn(20d);

       Assert.assertEquals(20d, mathApplication.add(10, 10), 0);
       reset(cs);
       Assert.assertEquals(20d, mathApplication.add(10, 10), 0);

   }


}


after reset,the effect of  when(mathApplication.add(10, 10)).thenReturn(20d); disappear.

13Mockito - Behavior Driven Developmen

//Given
given(calcService.add(20.0,10.0)).willReturn(30.0);

//when
double result = calcService.add(20.0,10.0);

//then
Assert.assertEquals(result,30.0,0);     


14 Advanced Topic - ArgumentCaptor

We have already set up the NotesPresenterTest with a mocked notes repository and view.

We have defined an ArgumentCaptor that captures parameters - we are using it to capture the callback for the NotesRepository when data is loaded by the presenter, so we can call it ourselves to simulate that the notes have been loaded already.

example

want to test this

  @Override
   public void loadNotes(boolean forceUpdate) {
//        mNotesView.setProgressIndicator(true);
//        if (forceUpdate) {
//            mNotesRepository.refreshData();
//        }
//
//        // The network request might be handled in a different thread so make sure Espresso knows
//        // that the app is busy until the response is handled.
//        EspressoIdlingResource.increment(); // App is busy until further notice
//
//        mNotesRepository.getNotes(new NotesRepository.LoadNotesCallback() {
//            @Override
//            public void onNotesLoaded(List<Note> notes) {
//                EspressoIdlingResource.decrement(); // Set app as idle.
//                mNotesView.setProgressIndicator(false);
//                mNotesView.showNotes(notes);
//            }
//        });
   }


 @Captor
   private ArgumentCaptor<LoadNotesCallback> mLoadNotesCallbackCaptor;

 // Callback is captured and invoked with stubbed notes
       verify(mNotesRepository).getNotes(mLoadNotesCallbackCaptor.capture());
       mLoadNotesCallbackCaptor.getValue().onNotesLoaded(NOTES);
//
//        // Then progress indicator is hidden and notes are shown in UI
       verify(mNotesView).setProgressIndicator(false);
       verify(mNotesView).showNotes(NOTES);





Power mock
Mockito不支持final方法,私有方法,静态方法,而PowerMock支持。所以这里也要介绍一下。但是还是不建议项目中使用,如果需要使用PowerMock才能测试,说明代码的可测试性不好,需要改进代码。一般都是历史遗留代码或者第三方库相关测试的时候才需要使用。


testCompile("org.powermock:powermock-module-junit4:1.6.2")
   testCompile("org.powermock:powermock-api-mockito:1.6.2")


public class Service {

   public static final String testStaticFinal() {
       System.out.println("testStaticFinal");
       return "static final";
   }

   private String testPrivate() {
       System.out.println("testPrivate");
       return "private";
   }

   public String testPrivateForPublic() {
       System.out.println("testPrivateForPublic");
       return testPrivate();
   }

   private String testPrivateWithArg(String arg) {
       System.out.println("testPrivateWithArg");
       return arg + "x";
   }
}


@RunWith(PowerMockRunner.class)
@PrepareForTest( { Service.class })
public class TestService {

   @Before
   public void initMocks() {
       mockStatic(Service.class);
   }

   @Test
   public void testTestStaticFinal() throws Exception {
       PowerMockito.when(Service.testStaticFinal()).thenReturn("mock1");
       assertEquals("mock1", Service.testStaticFinal());
   }

   @Test
   public void testPrivate() throws Exception {
       Service t = mock(Service.class);
       PowerMockito.when(t, "testPrivate").thenReturn("xxx");
       doCallRealMethod().when(t).testPrivateForPublic();
       assertEquals("xxx", t.testPrivateForPublic());
   }

   @Test
   public void testTestPrivateWithArg() throws Exception {
       Service t = spy(new Service());
       String arg = "dd";
       PowerMockito.when(t, "testPrivateWithArg", arg).thenReturn("lhc");
       assertEquals("lhc", t.getTestPrivateWithArg(arg));
   }
}