Whiteship's Note


[Mockito] mock 객체 쉽게 만들기

모하니?/Coding : 2009.07.27 21:15


이지목(easymock)을 사용할 때는 인터페이스의 목만 만들 수 있어서 불편했습니다. 물론, 이지목 확장팩(?)을 이용하면 클래스의 목객체도 만들 수 있었는데, 별도의 라이브러리를 추가해야 하는것이.. 좀 귀찮았죠. 요즘은 어떤지 몰겠습니다. 라이브러리 버전 올리면서 통합 할 법도 한데 말이죠.

암튼.. 저는 이지목보다 조금 더 간편하고 직관적인 라이브러리인 목킷투를 사용하고 있었는데, 예전에 살짝 공부한 상태에서 다시 별로 안 썼더니 그새에 많은 변화가 있었더군요. 그 중 가장 큰 변화가 애노테이션인 듯 한데요. 애노테이션을 이용해서 목객체를 아주 편리하게 만들 수 있었습니다.

@RunWith(MockitoJUnitRunner.class)
public class MemberServiceTest {

    MemberService memberService;
   
    @Mock MemberRepository mockMemberRepository;
    @Mock SignupSendService mockSignupSendService;

    @Before
    public void make() throws Exception {
        memberService = new MemberService();
        memberService.repository = mockMemberRepository;
        memberService.signupSendService = mockSignupSendService;
        assertNotNull(memberService.repository);
        assertNotNull(memberService.signupSendService);
    }

...

}

끝입니다. mock(MemberReposiroty.class); 같은 static 메서드 호출(이클립스에서 junit은 static import를 지원하지만 mockto는 지원하지 않아서 수동으로 static import 문을 적어줘야 하는 수고가 있죠.) 없이도 목 객체를 만들어(?) 사용할 수 있습니다. 그 비밀은 바로 @Runwith의 MockitoJUnitRunner에 있지요. 저 러너 설정하는 것이 귀찮다면 JUnit @Before 메서드에서 MockitoAnnotations.initMocks(this); 를 직접 호출해도 되지만, 개인적으로는 이걸 없애고 @RunWith를 사용하는 편이 코드가 더 깔끔한 듯 합니다.

목킷투~ 괜찮다~~
top

TAG @Mock, Mockito

[Mockito] void 메서드 stubbing 새로운 방법

Good Tools : 2009.05.13 16:41


참조: http://mockito.googlecode.com/svn/branches/1.4/javadoc/org/mockito/Mockito.html

링크에 있는 글대로 작성 해 보면

        stubVoid(mockWarManager).toThrow(new WarPackgingException()).on().packaging();

이렇게 됩니다.

"누가 뭘 던 진다 뭐 할 때."

새로운 형태로 작서한 코드는 다음과 같습니다.
       
        doThrow(new WarPackgingException()).when(mockWarManager).packaging();

"이걸 던진 다. 누가 뭐 할 때"

후자가 조금 더 짧죠.

ps: 매녈 좀 업데이트 해주시지 말입니다. 스프링은 매녈이 소스 코드를 앞서 간다는데...
top

TAG Mockito

Why OSAF 1. 테스트 코드를 익힐 수 있습니다.

OSAF : 2008.11.10 22:04


OSAF를 공개한지 한 달이 아직 안 됐습니다. 10월 23일에 공개했었죠. 지금까지 약 200에 가까운 다운로드를 기록하고 있지만, 전혀... 아무런... 반응이 없다는 것에는 가히 놀라울 뿐입니다. 그냥 제가 쓴 글의 댓글 몇 개 정도 뿐의 관심이 저에게 한 편으로는 아쉬움으로 또 다른 한 편으로는 오기로 다가옵니다.

완전 최첨단 프레임워크인 OSAF에 왜 이렇게 관심이 없을까. 고민을 많이 했습니다. 어렵나? 메이븐 떄문인가? 그거 없어도 되는데. 문서가 부족하긴 부족하고. 그래도 어떻게 이렇게 조용할 수가 있지. 홈피 디자인이 좀 구리긴 한데.. 그거 때문인가? ㅋ. OSAF 발음이 너무 어려운가? 별에 별 생각을 많이 했습니다. 당연히 기운도 빠집니다. OSAF를 공개한 건 어쩌면 OSAF에게 못씁짓을 한 건 아닌지 말이죠.(Max님의 '어디가서 밥은 먹고 다녀야 할텐데..' 라는 댓글이 생각납니다.)

긍정적으로 생각하기로 했습니다. 언젠가는 빛을 보겠지. 열심히 계속 가꾸다 보면 언젠간 알아주겠지. 하고 말이죠. 그래서 OSAF가 여러분에게 어떤 도움을 줄 수 있을지 생각하고 알려드리기로 했습니다. 그 중 첫 번째가 바로 테스트 코드입니다.

OSAF의 테스트 커버리지는 60%가 조금 넘습니다. (앞으로 차차 올릴 예정입니다.) 60%의 테스트 커버리지는 전부 OSAF 개발팀에서 직접 작성한 테스트 코드입니다. 어딘가에서 배껴온 코드가 절대로 아닙니다. 테스트는 초기에 JUnit과 EasyMock을 사용해서 작성 했었습니다. 물론 스프링 테스트 기능도 사용하고 있죠. 배포 직전에는 EasyMock을 Mockito로 교체하여 비슷한 테스트를 보다 깔끔하고 직관적이며 적은 수의 코드로 대체할 수 있었습니다. DBUnit을 확장하여 OSAF가 제공하는 테스트 케이스를 이용하면 DAO 테스트가 매우 간편해질 것 입니다.

이렇게 좋은데... 한 번 들여다 보고 뭐라고 해주시지 않으시겠어요? 좋다. 잘했다. 고맙다. 이런거 말구요. 이 부분의 테스트는 이해가 안 된다. 테스트가 조금 이상하다. 이 부분의 테스트는 왜 안했냐. 어려워서 그런거냐? 이 부분의 테스트는 이렇게 고치는게 좋치 않겠냐? 이런.. 반응이 제가 가장 좋아하는 반응이자 OSAF에게 거름을 주는 방법입니다.

소스 코드는 굳이 다운 받지 않아도(장기적으론 받아 두시면 좋겠지만..)

http://www.opensprout.org:9060/browse/OSAF/osaf/trunk

위 링크로 가시면 웹에서 직접 볼 수 있습니다. 소스 코드나 OSAF 와 관련하여 문제나 제안하고 싶은 것이 있다면 주저하지 마시고 이슈를 등록해 주세요.

http://www.opensprout.org/jira/secure/Dashboard.jspa


top


Mockito - 아규먼트 Matcher

모하니?/Coding : 2008.08.12 10:17


참조 : http://mockito.googlecode.com/svn/branches/1.4/javadoc/org/mockito/Mockito.html

  // 내장된 anyint() 아규먼트 매처를 사용해서 스텁 만들기.
  stub(mockedList.get(anyInt())).toReturn("element");
 
  // hamcrest가 제공하는 매처를 사용해서 스텁 만들기.
  stub(mockedList.contains(argThat(isValid()))).toReturn("element");
 
  // 다음은 "element"를 출력한다.
  System.out.println(mockedList.get(999));
 
  // 아규먼트 매처를 사용해서 verify()를 할 수도 있다.
  verify(mockedList).get(anyInt());
 
아규먼트 매처는 flexible한 검증과 스텁을 제공한다. 전체 매처는 여기서 확인할 수 있다.

주의할 것:

아규먼트 매처를 하나 사용하면, 다른 아규먼트들도 모두 매처로 표현해야 한다.

예:

   verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
   // 위와 같이 사용해야 한다. eq()도 아규먼트 매처니까 괜찮다.
  
   verify(mock).someMethod(anyInt(), anyString(), "third argument");
   // 이렇게 하면 안 된다. 아규먼트 매처없이 사용한 세번째 아규먼트 때문에 예외가 발생할 것이다.

Whiteship's Exercise

    @Test
    public void ilike() {
        Criteria c = mock(Criteria.class);
        CriteriaUtils.ilike(c, "name", "keesun", MatchMode.ANYWHERE);
        verify(c).add((Criterion) anyObject());
    }

    @Test
    public void ilikeWithNullValue() {
        Criteria c = mock(Criteria.class);
        CriteriaUtils.ilike(c, "name", null, MatchMode.ANYWHERE);
        verify(c, never()).add((Criterion) anyObject());
    }

top


Mockito - Verifying exact number of invocations / at least once / never

모하니?/Coding : 2008.07.31 17:59


Mockito 사용해서 정확한 메소드 호출 횟 수 / 최소한 한 번 / 전혀~ 한 번도 호출 안했는지 검증하기

  //mock 사용하기
  mockedList.add("once");
 
  mockedList.add("twice");
  mockedList.add("twice");
 
  mockedList.add("three times");
  mockedList.add("three times");
  mockedList.add("three times");
 
  //다음 두 번의 검증은 똑같다. 기본으로 times(1)를 사용하기 때문에..
  verify(mockedList).add("once");
  verify(mockedList, times(1)).add("once");
 
  //정확한 호출 횟 수 검증
  verify(mockedList, times(2)).add("twice");
  verify(mockedList, times(3)).add("three times");
 
  //neber()를 사용한 검증, times(0)과 같다.
  verify(mockedList, never()).add("never happened");
 
  //atLeastOnce()를 사용한 검증
  verify(mockedList, atLeastOnce()).add("three times");
 
Whiteship's Exercise

EasyMock Code

    @Test
    public void delete() {
        Member member = new Member();
        mockDao.delete(member);

        replay(mockDao);

        service.delete(member);

        verify(mockDao);
    }

Mockito Code

    @Test
    public void delete() {
        Member member = new Member();
        service.delete(member);
        verify(mockDao).delete(member);
    }



top

TAG Mockito

Mockito - How about some stubbing?

모하니?/Coding : 2008.07.31 17:25


참조 : http://mockito.googlecode.com/svn/branches/1.4/javadoc/org/mockito/Mockito.html

 //인터페이스가 아니라, 클래스의 mock 객체도 생성할 수 있다.
//easymock 보다 편하군요. easymcok은 extention 라이브러리를 설치해야 사용할 수 있죠.
 LinkedList mockedList = mock(LinkedList.class);
 
 //Stubbing
 stub(mockedList.get(0)).toReturn("first");
 stub(mockedList.get(1)).toThrow(new RuntimeException());
 
 //"first"를 출력할 것이고..
 System.out.println(mockedList.get(0));
 
 //RuntimeException을 던질 것이고..
 System.out.println(mockedList.get(1));
 
 //get(999)는 stubbing 하지 않았으니까 "null"을 출력할 겁니다.
 System.out.println(mockedList.get(999));
 
 //Stubbing 한 호출들은 암묵적으로 검증을 합니다. 여러분이 원하는 예외적인 흐름 상 해야만 한다면 해도 상관없습니다.
 //명시적으로 스텁 호출을 검증하는게 가능하긴 한데, 대부분의 경우 그럴필요까진 없습니다.
 verify(mockedList).get(0);

  • 기본적으로, 반환 값이 있는 모든 메소드들은, mock은 null을 반환하거나, 비어있는 콜렉션 또는 적절한 primitive 값을 반환합니다.(e.g: 0, false, ... for int/Integer, boolean/Boolean, ...).
  • 스텁 작업은 오버라이딩 할 수 있습니다. 예를 들어, 스텁으로 fixture를 만들어 둘텐데 그걸 테스트 메소드내에서 재정의할 수 있습니다.
  • 한 번 스텁을 만들어 두면 mocking한 메소드는 몇 번을 호출하든 상관없이 항상 스텁 값을 반환합니다.
  • 같은 메소드를 여러번 스텁 했을 때는 마지막에 스텁한 녀석이 더 중요합니다.
  • 명시적으로 스텁 호출을 검증하는 것이 가능하긴 한데, 대부분의 경우 불필요 합니다. 스텁 호출은 암묵적으로 검증을 합니다. 여러분이 작성한 코드의 실행 흐름에 따라 알아서 해줄 겁니다.

EasyMock Code

    @Test
    public void get() {
        int id = 1;
        Member member = new Member();
        member.setId(id);
        expect(mockDao.get(id)).andReturn(member);
       
        replay(mockDao);
       
        assertEquals(member, service.get(id));
       
        verify(mockDao);
    }

Mockito Code

    @Test
    public void get() {
        int id = 1;
        Member member = new Member();
        member.setId(id);

        stub(mockDao.get(id)).toReturn(member);
       
        assertThat(service.get(id), sameInstance(member));
    }


흠 오늘은 service 패키지 테스트들을 전부 Mockito로 바꿀려고 했는데, 오늘 안엔 다 못하겠군요. 오늘은 Mockito나 좀 더 공부하고 내일까지 해야겠네요.
top

TAG Mockito

expect -> run -> verify 스타일(ex. Easymock) 바이바이

모하니?/Coding : 2008.07.08 19:50


참조 : http://monkeyisland.pl/2008/02/01/deathwish/

이지목 스타일은 녹화 -> 플레이 -> 확인(expect -> run -> verify) 순으로 mocking 또는 stubbing 하는 거였습니다. 그러나 이 스타일은 다음과 같은 단점들이 있습니다.

1. 테스트 메소드가 지져분해짐.
- 이것 저것 예측/녹화를 해줘야 하는데 그게 테스트를 위해서가 아니라 Mock을 위해서 해줘야 한다는게 좀..

2. 자연스러운 테스트 스타일로 느껴지지 않는다.
- 예측을 한 담에 실행하는게 아니라, 실행 한 다음에 예측되는 Mock의 행위를 나열해 주는게 더 자연스럽다.

3. 테스트가 깨지기 쉽다.
- 새로운 기능을 추가하면, Mock을 사용한 테스트가 왕창 깨지는 경우가 발생한다.

4. 보다 자세한 실패 메시지를 보여줄 수 있었을 텐데...

5. 보다 가독성 좋게 만들 수 있었을 텐데...

그래서 상태 기반 테스트를 제공하는 Mockito를 강추 한다는거...

Mockito 홈에서 다음을 인용합니다.

No expect-run-verify also means that Mockito mocks are often ready without expensive setup upfront. They aim to be transparent and let the developer to focus on testing selected behavior rather than absorb attention.

Mockito has very slim API, almost no time is needed to start mocking. There is only one kind of mock, there is only one way of creating mocks. Just remember that stubbing goes before execution, verifications of interactions go afterwards. You'll soon notice how natural is that kind of mocking when test-driving java code.

즉 stubbing -> execution -> verification 라고 할 수 있겠네요. 훔.. 그래도 왠지 expect -> run -> verify 형태와 비슷해 보이네요.

사용법은 여기에 잘 나와있습니다.
top