2010-12-03 92 views
1

是否可以在同一類上單元測試方法調用(按順序以及它們被調用的次數)?單元測試方法調用(模板方法)?

即一個模板方法類似下面:

abstract class FooBarBaz { 

     public abstract void foo(); 
     public abstract void bar(); 
     public abstract void baz(); 

     // I want to create a unit test for this method, in the following order 
     public myTemplateMethod() { 
      foo(); // i want to check foo first; 
      bar(); // i want to check bar second; 
      baz(); // i want to check baz third; 
     } 
    } 

編輯 - 發佈的Mockito代碼實現

import junit.framework.TestCase; 
import org.mockito.Mockito; 

public class FooBarBazTest extends TestCase { 

    public void testMyTemplateMethodWithMockito() { 
     FooBarBaz mocked = Mockito.mock(FooBarBaz.class); 

     mocked.myTemplateMethod(); 

     Mockito.verify(mocked, Mockito.times(1)).foo(); 
     Mockito.verify(mocked, Mockito.times(1)).bar(); 
     Mockito.verify(mocked, Mockito.times(1)).baz(); 
    } 
} 

編輯 - 添加堆棧跟蹤

testMyTemplateMethodWithMockito(sample.FooBarBazTest) Time elapsed: 0.326 sec <<< FAILURE! 
Wanted but not invoked: 
fooBarBaz.foo(); 
-> at sample.FooBarBazTest.testMyTemplateMethodWithMockito(FooBarBazTest.java:14) 

However, there were other interactions with this mock: 
-> at sample.FooBarBazTest.testMyTemplateMethodWithMockito(FooBarBazTest.java:12) 

    at sample.FooBarBazTest.testMyTemplateMethodWithMockito(FooBarBazTest.java:14) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at junit.framework.TestCase.runTest(TestCase.java:168) 
    at junit.framework.TestCase.runBare(TestCase.java:134) 
    at junit.framework.TestResult$1.protect(TestResult.java:110) 
    at junit.framework.TestResult.runProtected(TestResult.java:128) 
    at junit.framework.TestResult.run(TestResult.java:113) 
    at junit.framework.TestCase.run(TestCase.java:124) 
    at junit.framework.TestSuite.runTest(TestSuite.java:232) 
    at junit.framework.TestSuite.run(TestSuite.java:227) 
    at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83) 
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59) 
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:115) 
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:102) 
    at org.apache.maven.surefire.Surefire.run(Surefire.java:180) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350) 
    at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021) 

回答

2

的確切數目用諷刺框架是好的,但如果你不想依賴外部依賴,只需創建一個實現你的抽象類的測試類。讓foo,bar,baz方法的抽象實現將字符串'foo','bar','baz'添加到共享列表中,然後在測試方法中聲明它們以正確順序位於列表中。

編輯 - 我用mockito和非模擬方式編寫了測試。他們都通過 - 我以前沒有使用過mockito,我可能想嘗試它....

import junit.framework.TestCase; 
import org.junit.Test; 

import java.util.ArrayList; 
import java.util.List; 

public class FooBarBazTests extends TestCase { 


    @Test 
    public void testMyTemplateMethod() { 
     List tracker = new ArrayList(); 
     SimpleFooBarBaz toTest = new SimpleFooBarBaz(tracker); 

     toTest.myTemplateMethod(); 


     assertEquals("foo", tracker.get(0)); 

     // more assertions 
    } 


    @Test 
    public void testMyTemplateMethodWithMockito() { 
     FooBarBaz mocked = mock(FooBarBaz.class); 

     mocked.myTemplateMethod(); 

     // times(1) is unnecessary, but explicit 
     verify(mocked, times(1)).foo(); 
     verify(mocked, times(1)).bar(); 
     verify(mocked, times(1)).baz(); 
    } 

    class SimpleFooBarBaz extends FooBarBaz { 


     List tracker; 

     SimpleFooBarBaz(List tracker) { 
      this.tracker = tracker; 
     } 

     public void foo() { 
      tracker.add("foo"); 
     } 

     @Override 
     public void bar() { 
      //To change body of implemented methods use File | Settings | File Templates. 
     } 

     @Override 
     public void baz() { 
      //To change body of implemented methods use File | Settings | File Templates. 
     } 

     // others there 

    } 

} 
4

Mockito看看它內置了這種行爲。

從他們的文檔:
6.驗證爲了

List firstMock = mock(List.class); 
List secondMock = mock(List.class); 

//using mocks 
firstMock.add("was called first"); 
secondMock.add("was called second"); 

//create inOrder object passing any mocks that need to be verified in order 
InOrder inOrder = inOrder(firstMock, secondMock); 

//following will make sure that firstMock was called before secondMock 
inOrder.verify(firstMock).add("was called first"); 
inOrder.verify(secondMock).add("was called second"); 

和:
4.驗證調用/至少爲x /從未

//using mock 
mockedList.add("once"); 

mockedList.add("twice"); 
mockedList.add("twice"); 

mockedList.add("three times"); 
mockedList.add("three times"); 
mockedList.add("three times"); 

//following two verifications work exactly the same - times(1) is used by default 
verify(mockedList).add("once"); 
verify(mockedList, times(1)).add("once"); 

//exact number of invocations verification 
verify(mockedList, times(2)).add("twice"); 
verify(mockedList, times(3)).add("three times"); 

//verification using never(). never() is an alias to times(0) 
verify(mockedList, never()).add("never happened"); 

//verification using atLeast()/atMost() 
verify(mockedList, atLeastOnce()).add("three times"); 
verify(mockedList, atLeast(2)).add("five times"); 
verify(mockedList, atMost(5)).add("three times"); 
+0

@ javamonkey79這個問題是我需要調用我的測試用例中的方法才能看到如果它被調用。 – Joopiter 2010-12-03 01:47:53

+2

@joopiter,我想他只是向你展示文檔,你需要嘲笑你的抽象類,設置期望值,然後調用你的方法對測試,然後驗證 – hvgotcodes 2010-12-03 01:56:45