programing

최종 방법 조롱

nasanasas 2020. 12. 8. 08:16
반응형

최종 방법 조롱


mockito를 사용하여 최종 방법으로 일부 클래스를 모의해야합니다. 나는 이와 같은 것을 썼다

@Test
public void test() {
    B b = mock(B.class);
    doReturn("bar called").when(b).bar();   
    assertEquals("must be \"overrided\"", "bar called", b.bar());
    //bla-bla
}


class B {
    public final String bar() {
        return "fail";
    }
}

그러나 그것은 실패합니다. 나는 약간의 "해킹"을 시도했고 그것은 작동한다.

   @Test
   public void hackTest() {
        class NewB extends B {
            public String barForTest() {
                return bar();
            }
        }
        NewB b = mock(NewB.class);
        doReturn("bar called").when(b).barForTest();
        assertEquals("must be \"overrided\"", "bar called", b.barForTest());
    }

작동하지만 "냄새".

그렇다면 올바른 방법은 어디입니까?

감사.


Mockito에서는 최종 메소드를 조롱하는 기능이 지원되지 않습니다.

Jon Skeet이 언급했듯이 최종 방법에 대한 종속성을 피할 수있는 방법을 찾아야합니다. 즉, 바이트 코드 조작 (예 : PowerMock 사용)을 통한 몇 가지 방법이 있습니다.

Mockito 및 PowerMock의 비교는 구체적으로 일을 설명 할 것이다.


로부터 Mockito 자주 묻는 질문 :

Mockito의 한계는 무엇입니까

  • 최종 메서드를 모의 할 수 없습니다. 실제 동작은 예외없이 실행됩니다. Mockito는 최종 방법을 조롱하는 것에 대해 경고 할 수 없으므로주의해야합니다.

Powermock을 Mockito와 함께 사용할 수 있으며 B.class를 하위 클래스화할 필요가 없습니다. 이것을 테스트 클래스의 맨 위에 추가하십시오.

@RunWith(PowerMockRunner.class)
@PrepareForTest(B.class)

@PrepareForTestPowermock이 최종 및 정적 메서드를 모의 할 수 있도록 B.class를 계측하도록 지시합니다. 이 접근 방식의 단점은 Spring 테스트 실행기와 같은 다른 테스트 실행기를 사용할 수 없도록하는 PowerMockRunner를 사용해야한다는 것입니다.


Mockito 2는 이제 최종 방법을 조롱하는 것을 지원하지만 이것은 "인큐베이팅"기능입니다. 활성화하려면 여기에 설명 된 몇 가지 단계가 필요합니다. https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of- 최종 수업 방법


Mockito 2.x는 이제 최종 메서드 및 최종 클래스 스터 빙을 지원합니다.

문서에서 :

Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:

mock-maker-inline

After you create this file you can do:

final class FinalClass {
  final String finalMethod() { return "something"; }
}

FinalClass concrete = new FinalClass(); 

FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");

assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());

In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.


Assuming that B class is as below:

class B {
    private String barValue;
    public final String bar() {
        return barValue;
    }
    public void final setBar(String barValue) {
        this.barValue = barValue;
    }
}

There is a better way to do this without using PowerMockito framework. You can create a SPY for your class and can mock your final method. Below is the way to do it:

@Test
public void test() {

    B b  = new B();
    b.setBar("bar called") //This should the expected output:final_method_bar()
    B spyB = Mockito.spy(b);
    assertEquals("bar called", spyB.bar());

}

I just did this same thing. My case was that I wanted to ensure the method didn't "Cause" an error but since it's a catch/log/return method I couldn't test for it directly without modifying the class.

I wanted to simply mock the logger I passed in, but something about mocking the "Log" interface didn't seem to work and Mocking a class like "SimpleLog" didn't work because those methods are final.

I ended up creating an anonymous inner class extending SimpleLog that overrid the base-level "log(level, string, error)" method that the others all delegate to, then just waiting for a call with a "level" of 5.

In general, extending a class for behavior isn't really a bad idea, might be preferable to mocking anyway if it's not too complicated.

참고URL : https://stackoverflow.com/questions/3793791/final-method-mocking

반응형