2014-10-21 5 views
1

입력 문자열 (필자의 경우 StringBuilder)이 2048자를 넘으면 내 메서드가 예외를 반환합니다. 우리가 Mockito를 사용하여 최종 수업을 모의 할 수 없기 때문에, 누군가가 이것을 어떻게 테스트하는지 알려줄 수 있습니까?Mockito : 긴 길이의 문자열을 사용하는 메서드를 테스트하십시오.

한 가지 방법은 실제로 길게 멍청한 문자열을 전달하는 것입니다. 이것을 테스트 할 수있는 쉬운 방법이 있습니까?

+0

나는이 문제를 이해하지 못합니다. 조금 더 설명하거나 코드를 게시 할 수 있습니까? throw 및 예외를 확인하고 확인하려는 경우 @Test 주석 (expected = YourException.class)에 매개 변수를 추가해야합니다. –

+0

왜 문자열을 전달하는 것이 어리 석 었습니까? 나는 Mock을 너무 많이 사용하는 것을 보았습니다. –

+0

레코드의 경우 비슷한 [mockito를 사용하여 String을 조롱하는 방법?] (StackOverflow에 대한 질문이 이미 있습니다.) (http://stackoverflow.com/q/1079239/1426891). 나는 그것이 중복이라고 생각하지 않는다. 그러나이 질문은 도서관 기능 대신 조롱 전략에 관한 것이다. –

답변

1

Mockito의 개발자는 모의 객체를 전달하는 것이 실제 String을 만드는 것보다 쉽습니다. 그러나 실제 문자열을 만드는 은 여전히 ​​테스트를위한 가장 좋은 옵션입니다.


당신은 제대로 Mockito의 조용히 그것을 위해 서브 클래스를 생성하는 프록시 또는 바이트 코드 생성을 사용할 수 있도록 문자열, final이라고 지적했다. 대신 Powermock을 사용해야합니다. 실제로 은 실제 구현 대신 조롱 된 String.length()를 사용하기 위해 사용자 정의 클래스 로더를 사용하여 테스트중인 클래스의 바이트 코드를 다시 작성합니다. 어느 쪽이든, 그것은 간단한 문자열을 모방하는 엄청난 작업이며, 대안보다 더 많은 테스트 시간과 메모리를 필요로합니다.

String이 final이 아니더라도, 당신은 (아마도) 단지 String의 서브 세트만을 조롱하기 때문에 여전히 취성 테스트를 작성하고있을 것입니다. Mockito는 unmocked codePointCount 되돌아 볼 수 있기 때문에

public boolean isStringValid(String input) { 
    // Handle Unicode surrogate pairs. 
    return input.codePointCount(0, input.length()) <= 1024; // NOT 2048 
} 

... 갑자기 테스트가 잘못 전달합니다

when(mockString.length()).thenReturn(2048); 

을하지만, 어느 날, 당신의 구현에 회전이 가정에서, 당신은 쓸 수 기본값 int 반환 값은 0입니다. 불완전한 모의 객체를 사용하는 테스트는 실제 객체를 사용하는 테스트보다 덜 탄력 있고 덜 가치가있는 이유 중 하나입니다.

하지만 완전한 mock은 무엇입니까? 그런 다음 codePointCount을 조롱 할 수 있습니다. 결론적으로 말하자면, 당신은 상속 된 String 객체를 상상할 수 있습니다.이 객체는 여러분이 지정한 모든 호출에 대한 값을 올바르게 반환합니다. 이 시점에서 String을 다시 구현하여 가독성을 희생 시키며, 거의 아무 이유없이 Java 역사에서 가장 검증되고 가장 명백한 구현 중 하나를 재현하는 많은 엔지니어링 시간을 소비했습니다. 뭐든지, 나를 꽤 바보 같습니다.

몇 가지 가이드 라인 :

  • 모의 구현 소유하지 않은하지 마십시오. Mockito는 예를 들어 모의 구현에서 final 표시로 묶여 있으므로 다른 유형을 조롱하는 것은 나쁜 습관입니다. 다른 팀의 구현 세부 사항으로 인해 테스트가 중단 될 수 있다는 것은 매우 나쁜 징조입니다.

  • 실제로 테스트되고 인증 된 인스턴스를 사용할 수있는 경우 객체를 모의하지 마십시오. 이 경우에 조롱 할만한 이유가 거의 없으며 그렇게하면 테스트가 불필요하게 취약해질 수 있습니다.

  • 특히 데이터 객체를 모의하지 마십시오. 예를 들어 setFoo과 일치하는 getFoo에 의존하며 equalshashCode에 의존 할 수도 있습니다.어쨌든 잘 설계된 데이터 객체에는 외부 종속성이 없습니다.

  • 가능한 경우 구현 클래스 대신 모의 인터페이스. 이는 모의 작업 방식을 변경하는 구현 세부 사항으로부터 당신을 보호합니다.

  • 서비스 호출을하거나 테스트에 적합하지 않은 리소스를 사용하는 데이터 개체를 발견하면 서비스 메서드를 별도의 잘 알려진 함수로 추출하는 것과 같이 테스트 가능성을 높이기 위해 클래스를 리팩토링 할 수 있습니다. 인터페이스를 추출하고 custom reusable test doubles을 만듭니다. 테스트는 클래스의 최상급 사용자 여야하며 테스트 가능성을 위해 제어하는 ​​클래스를 변경하거나 제어하지 않는 클래스를 변경하는 것이 특권입니다. 나는 종종 이러한 클래스가 프로덕션 환경에서 사용하기 쉽게 만들어 준다는 것을 발견했습니다.

+0

내가 언급 한 모든 내용에 동의합니다. 문자 한도를 2048에서 20K로 변경하거나 더 크게 설정할 수 있다면 어떻게 될까요? 이 경우 여전히 실제 문자열을 만드는 것이 좋습니다? – Sachin

+1

** 예, 생각할 필요가 없습니다. ** 테스트중인 시스템이 실제 문자열을 wild-2k, 20k, 2M에서 찾을 수있는 경우 실제 String을 사용하십시오. 문자열은 테스트 또는 프로덕션에서 올바른 데이터 유형이 아닐 수도 있습니다. 왜냐하면 문자열은 연속적으로 변하지 않는 불변의 메모리 블록이기 때문입니다. 내 디자인을 다시 한 번 확인하고 CharSequence (작고 조롱 가능한 인터페이스)로 전환 한 다음 [Rope] (http://en.wikipedia.org/wiki/Rope_ (data_structure)) 프로덕션 환경에서 사용하는 것이 좋습니다. 주의 : CharSequence는 어쨌든'toString'을 노출합니다. :) –

0

IMHO, 여기에 Mockito 필요, 그냥 알려진 길이 String을 (여기에 내가 평민 - 랭 RandomStringUtils를 사용)을 생성 뭔가를 사용하지 않습니다. 또한 ExpectedException을 사용하여 예외를 테스트 할 수 있습니다.

public class MyClassTest { 
    private static int LIMIT = 2048; 
    private static String TEST_STRING1 = RandomStringUtils.random(LIMIT); 
    private static String TEST_STRING2 = RandomStringUtils.random(LIMIT + 1); 

    @Rule 
    public ExpectedException ee = ExpectedException.none(); 

    private MyClass myClass = new MyClass(); 

    @Test 
    public void smallStringShouldBeOk() { 
     myClass.myMethod("foobar"); // OK if no exception or assert on a returned value 
    } 

    @Test 
    public void edgeCaseStringShouldThrow() { 
     ee.expect(SomeException.class) 
     ee.expectMessage("some message"); 

     myClass.myMethod(TEST_STRING1); 
    } 

    @Test 
    public void tooLongStringShouldThrow() { 
     ee.expect(SomeException.class) 
     ee.expectMessage("some message"); 

     myClass.myMethod(TEST_STRING2); 
    } 
} 
관련 문제