문제

고 싶을 테스트하는 추상 클래스입니다.확실히,나는 수 동 모의 에서 상속되는 클래스입니다.

을 할 수 있을 사용하여 이를 조롱하는 프레임워크(나를 사용하여 Mockito)신의 손을 만드는 내 모?방법?

도움이 되었습니까?

해결책

다음 제안 "실제"서브 클래스를 만들지 않고 추상 클래스를 테스트하겠습니다. ~이다 서브 클래스.

사용 Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS), 그런 다음 호출 된 추상적 인 방법을 조롱하십시오.

예시:

public abstract class My {
  public Result methodUnderTest() { ... }
  protected abstract void methodIDontCareAbout();
}

public class MyTest {
    @Test
    public void shouldFailOnNullIdentifiers() {
        My my = Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS);
        Assert.assertSomething(my.methodUnderTest());
    }
}

참고 :이 솔루션의 아름다움은 가지다 절대 호출되지 않는 한 추상 방법을 구현합니다.

솔직한 의견으로는 스파이에 인스턴스가 필요하기 때문에 스파이를 사용하는 것보다 깔끔합니다. 즉, 추상 클래스의 즉각적인 서브 클래스를 만들어야합니다.

다른 팁

초록을 만지지 않고 콘크리트 방법을 테스트 해야하는 경우 사용할 수 있습니다. CALLS_REAL_METHODS (보다 Morten의 대답), 그러나 테스트중인 구체적인 방법이 일부 초록 또는 구현되지 않은 인터페이스 방법을 호출하는 경우, 이것은 작동하지 않습니다. Mockito는 "Java 인터페이스에서 실제 방법을 호출 할 수 없다"고 불평합니다.

(예, 그것은 거친 디자인이지만 일부 프레임 워크 (예 : 태피스트리 4)는 당신에게 그것을 강요합니다.)

해결 방법은이 접근법을 뒤집는 것입니다. 일반적인 모의 행동 (예 : 모든 것이 조롱/스터브)을 사용하고 사용합니다. doCallRealMethod() 테스트중인 콘크리트 방법을 명시 적으로 부릅니다. 예를 들어

public abstract class MyClass {
    @SomeDependencyInjectionOrSomething
    public abstract MyDependency getDependency();

    public void myMethod() {
        MyDependency dep = getDependency();
        dep.doSomething();
    }
}

public class MyClassTest {
    @Test
    public void myMethodDoesSomethingWithDependency() {
        MyDependency theDependency = mock(MyDependency.class);

        MyClass myInstance = mock(MyClass.class);

        // can't do this with CALLS_REAL_METHODS
        when(myInstance.getDependency()).thenReturn(theDependency);

        doCallRealMethod().when(myInstance).myMethod();
        myInstance.myMethod();

        verify(theDependency, times(1)).doSomething();
    }
}

추가로 업데이트 :

비 공동 방법의 경우 사용해야합니다 thenCallRealMethod() 대신, 예를 들어 :

when(myInstance.myNonVoidMethod(someArgument)).thenCallRealMethod();

그렇지 않으면 Mockito는 "미완성 된 스터브 탐지"를 불평 할 것입니다.

스파이를 사용하여이를 달성 할 수 있습니다 (최신 버전의 Mockito 1.8+를 사용하십시오).

public abstract class MyAbstract {
  public String concrete() {
    return abstractMethod();
  }
  public abstract String abstractMethod();
}

public class MyAbstractImpl extends MyAbstract {
  public String abstractMethod() {
    return null;
  }
}

// your test code below

MyAbstractImpl abstractImpl = spy(new MyAbstractImpl());
doReturn("Blah").when(abstractImpl).abstractMethod();
assertTrue("Blah".equals(abstractImpl.concrete()));

조롱하는 프레임워크 설계를 간편하게 모의 종속성의 클래스는 테스트입니다.을 사용할 때 조롱하는 프레임워크를 모의 클래스,대부분의 프레임워크가 동적으로 서브 클래스를 이용해서 만들어진,그리고 대체 방법을 구현한 코드를 검출하는 경우 이 메소드가 호출하고 반환하는 가짜 값입니다.

테스트할 때는 추상 클래스는 실행할 non-추상적인 방법의 주제 테스트(SUT),그래서 조롱 framework 지 않습니다.

일부의 혼란은 질문에 대한 답변을 연결했을 손으로 만들은 모의 확장에서 추상 클래스입니다.나는 이러한 등급 a mock.모의 클래스로 사용되는 대체에 대한 의존성,프로그램으로 기대를 쿼리할 수 있습을 보면 그 기대를 만났다.

대신,나를 정의하는 것이 좋 non-추상 클래스의 추상 클래스에서 당신의 테스트입니다.는 경우 그 결과에 너무 많은 코드,그보다도는 당신의 클래스가 어렵습니다.

대체 솔루션의 테스트 사건 자체를 추상적으로,추상적인 방법을 만들기 위한 SUT(즉,테스트 사례 사용 템플릿 방법 디자인 패턴).

사용자 지정 답변을 사용해보십시오.

예를 들어:

import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class CustomAnswer implements Answer<Object> {

    public Object answer(InvocationOnMock invocation) throws Throwable {

        Answer<Object> answer = null;

        if (isAbstract(invocation.getMethod().getModifiers())) {

            answer = Mockito.RETURNS_DEFAULTS;

        } else {

            answer = Mockito.CALLS_REAL_METHODS;
        }

        return answer.answer(invocation);
    }
}

추상적 인 방법을 위해 모의를 반환하고 구체적인 방법에 대한 실제 방법을 호출합니다.

추상 클래스를 조롱하는 것에 대해 기분이 나쁘게 만드는 것은 기본 생성자 YouabStractClass ()가 MOCK에서 부름을받지 않거나 모의 속성 (예 : 목록 속성을 초기화하는 방법이없는 것 같지 않다는 사실입니다. 빈 배열리스트 또는 링크 사전 목록으로).

내 추상 클래스 (기본적으로 클래스 소스 코드가 생성됨)는 목록 요소에 대한 종속성 세터 주입 또는 목록 요소를 초기화하는 생성자 (수동으로 추가하려고 시도)를 제공하지 않습니다.

클래스 속성만이 기본 초기화를 사용합니다. 개인 목록 dep1 = new ArrayList; 개인 목록 DEP2 = New Arraylist

따라서 실제 객체 구현 (예 : 단위 테스트 클래스의 내부 클래스 정의, 추상 방법을 무시하고)을 사용하지 않고 실제 객체 (적절한 필드 초기화를 수행)를 사용하지 않고 추상 클래스를 조롱 할 수있는 방법이 없습니다.

PowerMock만이 여기서 더 도움이 될 것이 너무 나쁩니다.

테스트 클래스가 테스트중인 클래스와 동일한 패키지 (다른 소스 루트 아래)에 있다고 가정하면 단순히 모의를 만들 수 있습니다.

YourClass yourObject = mock(YourClass.class);

다른 방법과 마찬가지로 테스트하려는 방법을 호출하십시오.

슈퍼 방법을 호출하는 구체적인 방법에 대한 기대와 함께 호출되는 각 방법에 대한 기대치를 제공해야합니다. Mockito로 어떻게 수행 할 것인지 확실하지 않지만 EasyMock에서는 가능하다고 생각합니다.

이 모든 일은 구체적인 인스턴스를 만드는 것입니다. YouClass 각 추상 방법의 빈 구현을 제공하려는 노력을 절약합니다.

제쳐두고, 나는 종종 테스트에서 추상 클래스를 구현하는 것이 유용하다고 생각합니다. 여기서 공개 인터페이스를 통해 테스트하는 예제 구현 역할을하지만 이는 추상 클래스가 제공하는 기능에 따라 다릅니다.

테스트에서 익명의 클래스로 추상 클래스를 확장 할 수 있습니다. 예를 들어 (Junit 4 사용) :

private AbstractClassName classToTest;

@Before
public void preTestSetup()
{
    classToTest = new AbstractClassName() { };
}

// Test the AbstractClassName methods.

익명의 수업을 인스턴스화하고 모의를 주입 한 다음 해당 수업을 테스트 할 수 있습니다.

@RunWith(MockitoJUnitRunner.class)
public class ClassUnderTest_Test {

    private ClassUnderTest classUnderTest;

    @Mock
    MyDependencyService myDependencyService;

    @Before
    public void setUp() throws Exception {
        this.classUnderTest = getInstance();
    }

    private ClassUnderTest getInstance() {
        return new ClassUnderTest() {

            private ClassUnderTest init(
                    MyDependencyService myDependencyService
            ) {
                this.myDependencyService = myDependencyService;
                return this;
            }

            @Override
            protected void myMethodToTest() {
                return super.myMethodToTest();
            }
        }.init(myDependencyService);
    }
}

가시성은 있어야한다는 점을 명심하십시오 protected 재산을 위해 myDependencyService 추상 클래스의 ClassUnderTest.

화이트 박스.invokeMethod(..)이 편리할 수 있습니다 이 경우에.

Mockito는이를 통해 추상 클래스를 조롱 할 수 있습니다 @Mock 주석:

public abstract class My {

    public abstract boolean myAbstractMethod();

    public void myNonAbstractMethod() {
        // ...
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyTest {

    @Mock(answer = Answers.CALLS_REAL_METHODS)
    private My my;

    @Test
    private void shouldPass() {
        BDDMockito.given(my.myAbstractMethod()).willReturn(true);
        my.myNonAbstractMethod();
        // ...
    }
}

단점은 생성자 매개 변수가 필요한 경우 사용할 수 없다는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top