Android 단위 테스트 팁

과거에는 작업을 완료하기 위해 단일 테스트를 수행했지만 지금은 실제로 코드의 정확성을 테스트하는 것이며 함정에 빠지기 쉽습니다.그 전에는 요약을 작성하지 않았으며 지금은 몇 가지를 기억합니다. 좋은 단일 테스트 방법과 내가 밟은 함정.

1. 로그 출력

이게 가장 중요한 것 같아요 코드 테스트를 할 때 출력 로그에 따라 코드가 어디로 가는지 판단해야 합니다 예전에는 라인 커버리지에 너무 신경을 많이 썼는데 이 부분은 크게 신경을 안쓰고 .. 이 부분을 처리하는데 시간이 많이 걸렸습니다.

Log.xxx는 로그를 콘솔에 출력할 수 없으며 System.out.print만 볼 수 있으므로 출력을 System.out.print로 변환하려면 모의 로그의 정적 메서드가 필요합니다.

PowerMockito.mockStatic(Log.class);
Mockito.when(Log.e(anyString(), anyString())).then(new Answer<Void>() {
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        String TAG = (String) invocation.getArguments()[0];
        String msg = (String) invocation.getArguments()[1];
        System.err.println(String.format("Error: /%s: %s", TAG, msg));
        return null;
    }
});

다른 로그 수준도 비슷하며 일부 주요 메서드는 나중에 호출하기 편리한 클래스로 작성할 수 있습니다.

여기서 PowerMockito는 반환 값을 비어 있는 것으로 조롱할 수 없다는 점에 유의해야 합니다(아마도 찾지 못했을 수도 있습니다).

2. 테스트 템플릿

일반적으로 Robolectric과 PowerMock은 함께 사용하지만 매칭 시 일부 파라미터를 설정해야 하며, 그렇지 않으면 둘이 충돌할 가능성이 높으며, 예를 들어 둘이 함께 있을 경우 Robolectric 아래의 RuntimeEnvironment.application이 null이 되므로 템플릿을 준비합니다. 통합 테스트 환경과 동일:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
// 这个就是为了避免PowerMock把Robolectric的一些东西mock掉
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareForTest({Log.class})

public class TestTemplate {
    // 这个相当于setUp()函数,不加是mock不了的.
    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        MockLogUtils.mockLog();
    }
}

의존하다:

testImplementation "org.powermock:powermock-module-junit4:1.6.6"
testImplementation "org.powermock:powermock-module-junit4-rule:1.6.6"
testImplementation "org.powermock:powermock-api-mockito:1.6.6"
testImplementation "org.powermock:powermock-classloading-xstream:1.6.6"
testImplementation 'org.robolectric:robolectric:3.8'
// 以下非必须,robolectric还有很多这样的影子库
testImplementation 'org.robolectric:shadows-httpclient:3.3.2'

추신: 이 템플릿에는 결함이 있습니다. 컨텍스트를 모의하려는 경우 robo와 충돌합니다. 이 경우 다른 테스트 클래스를 만들고 PowerMock.runner를 사용하여 테스트하십시오.

3. 테스트 기술:

(1) 가지를 덮는 것 외에도
빈 매개변수 전달, 함수 여러 번 호출, 실행 시간에 주의 등 경계를 고려해야 합니다.

(2) Whitebox는 좋은 것입니다:
그것은 많은 반사 함수, setInternalState 및 getInternalState를 완료하여 테스트 중인 개체의 속성 변경을 설정하고 얻는 데 직접 도움이 됩니다.일부 함수가 실행된 후 확인 또는 확인을 통해 확인할 수 있습니다. 주장하다 .

(3) 테스트 예외 던지기:
Test(expect = Exception.class)에서 expect는 원하는 예외를 추가합니다.

(4) when...thenReturn과 doReturn...when의 차이점:
(a)when(...) thenReturn(...)은 실제 메서드를 호출하지 않으려는 경우 실제 메서드를 호출합니다.
(b)doReturn(…) when(…)은 실제 메서드를 호출하지 않습니다 .

(5) PrepareForTest의 문제.
최근에 문제점을 발견하여 클래스 레벨에서 PrepareForTest({Log.class}) 애노테이션을 추가했고 메소드를 테스트할 때 메소드 레벨에서 PrepareForTest({XXX.class})도 추가했습니다. 이 메서드를 실행할 때 로그라고 합니다. .class 메서드에는 준비가 없습니다. 이유를 모르겠습니다. 일단 준비가 분리되면 작동하지 않는다는 것을 알았습니다. 두 클래스가 클래스 또는 메서드에서 준비되면 동시에 괜찮을 것입니다.

(6) 테스트 비동기 메서드 테스트
할 메서드가 새 스레드 내에서 실행하거나 스레드 풀을 사용하여 실행하는 것과 같이 테스트할 메서드가 비동기적으로 실행되는 경우 Test 메서드가 System.exit( ) 드롭, 자식 스레드가 현재 생성되지 않았을 수 있습니다. Test 메서드의 끝에서 Thread.sleep()에 살고 자식 스레드가 실행될 때까지 기다릴 수 있습니다.

(7) Test Handler
Handler는 Android 고유이므로 로컬 단일 테스트 중에 직접 건너뜁니다.

 @Mock
Handler handler;

@Before
@PrepareForTest({ Handler.class})
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);

    PowerMockito.mock(Handler.class);
    // mock它的post方法,其它类似
    PowerMockito.doAnswer(new Answer<Object>() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            Runnable runnable = (Runnable) invocation.getArguments()[0];
            runnable.run();
            return null;
        }
    }).when(handler).post((Runnable) any());
}

(8) 객체를 스파이하고 반환된 객체를 조롱할 수 있습니다. 스파이와 모크의 차이점은 다음과 같습니다.
①모킹된 객체는 완전히 가짜이며 이를 호출하는 메서드는 호출되지 않으며 일반적으로 테스트 객체의 종속 객체에 사용됩니다.
②spy, 실제 메서드를 호출해야 한다면 이 클래스 객체를 실제로 생성해야 하는데, 이때 일부 메서드를 모킹하려면 obj를 모킹할 수 없기 때문에 when(obj)를 호출할 때 오류가 보고됩니다. 이때 모의하고 싶다면 spy(obj)만 하면 새로운 obj가 반환되며 모의할 수 있습니다. 여전히 실제 메서드를 호출합니다.

추천

출처blog.csdn.net/aa642531/article/details/109256999