무작위 이벤트를 기반으로 코드를 다루기 위해 테스트 사례를 어떻게 디자인 할 수 있습니까?


15

예를 들어, 코드가 0-10에서 임의의 int를 생성하고 각 결과에 대해 다른 분기를 사용하는 경우 이러한 코드에서 100 % 명령문 적용 범위를 보장하기 위해 테스트 스위트를 어떻게 설계 할 수 있습니까?

Java에서 코드는 다음과 같습니다.

int i = new Random().nextInt(10);
switch(i)
{
    //11 case statements
}

답변:


22

랜덤에 대한 래퍼를 만들어야한다는 전적으로 동의하는 David의 대답을 확장하십시오 . 나는 비슷한 질문 에서 앞서 그것에 대해 거의 같은 대답을 썼 으므로 여기에 "Cliff 's notes version"이 있습니다.

먼저 래퍼를 인터페이스 (또는 추상 클래스)로 작성해야합니다.

public interface IRandomWrapper {
    int getInt();
}

이에 대한 구체적인 클래스는 다음과 같습니다.

public RandomWrapper implements IRandomWrapper {

    private Random random;

    public RandomWrapper() {
        random = new Random();
    }

    public int getInt() {
        return random.nextInt(10);
    }

}

수업이 다음과 같다고 가정 해보십시오.

class MyClass {

    public void doSomething() {
        int i=new Random().nextInt(10)
        switch(i)
        {
            //11 case statements
        }
    }

}

IRandomWrapper를 올바르게 사용하려면 클래스를 수정하여 생성자 또는 설정자를 통해 멤버로 가져와야합니다.

public class MyClass {

    private IRandomWrapper random = new RandomWrapper(); // default implementation

    public setRandomWrapper(IRandomWrapper random) {
        this.random = random;
    }

    public void doSomething() {
        int i = random.getInt();
        switch(i)
        {
            //11 case statements
        }
    }

}

이제 래퍼를 조롱하여 래퍼로 클래스의 동작을 테스트 할 수 있습니다. 조롱 프레임 워크를 사용 하여이 작업을 수행 할 수 있지만 직접 수행하는 것도 쉽습니다.

public class MockedRandomWrapper implements IRandomWrapper {

   private int theInt;    

   public MockedRandomWrapper(int theInt) {
       this.theInt = theInt;
   }

   public int getInt() { 
       return theInt;
   }

}

당신의 수업은 IRandomWrapper당신 처럼 보이는 것을 기대하기 때문에 이제는 조롱 한 것을 사용하여 시험에서 행동을 강제 할 수 있습니다. 다음은 JUnit 테스트의 예입니다.

@Test
public void testFirstSwitchStatement() {
    MyClass mc = new MyClass();
    IRandomWrapper random = new MockedRandomWrapper(0);
    mc.setRandomWrapper(random);

    mc.doSomething();

    // verify the behaviour for when random spits out zero
}

@Test
public void testFirstSwitchStatement() {
    MyClass mc = new MyClass();
    IRandomWrapper random = new MockedRandomWrapper(1);
    mc.setRandomWrapper(random);

    mc.doSomething();

    // verify the behaviour for when random spits out one
}

도움이 되었기를 바랍니다.


3
이것에 전적으로 동의합니다. 임의의 이벤트 특성을 제거하여 임의의 이벤트를 테스트합니다. 타임 스탬프에도 동일한 이론을 사용할 수 있습니다.
Richard

3
참고 : 객체에 필요한 다른 객체를 제공하는 대신이
테크닉을

23

임의 생성 코드를 클래스 또는 메소드로 랩핑 한 다음 테스트 중에이를 모의 / 재정 의하여 원하는 값을 설정하여 테스트를 예측할 수 있습니다.


5

지정된 범위 (0-10)와 지정된 세분성 (정수)이 있습니다. 따라서 테스트 할 때 임의의 숫자로 테스트하지 않습니다. 각 사례에 차례로 맞는 루프 내에서 테스트합니다. case 문을 포함하는 하위 함수에 난수를 전달하면 하위 함수를 테스트 할 수 있습니다.


더 나은 내가 제안한 것보다 (더 간단하기 때문에), 나는 :) 내 upvotes를 전송할 수 있으면 좋겠다
데이비드

실제로 둘 다해야합니다. 모의 RandomObject와 테스트는 각각 개별적으로 지점, 테스트 실제 RandomObject 반복적으로 테스트를. 전자는 단위 테스트이고 후자는 통합 테스트와 비슷합니다.
sleske

3

PowerMock 라이브러리를 사용하여 Random 클래스를 조롱하고 nextInt () 메소드를 스텁하여 예상 값을 리턴 할 수 있습니다. 원하지 않는 경우 원래 코드를 변경할 필요가 없습니다.

PowerMockito를 사용하고 있으며 비슷한 방법을 테스트했습니다. JUnit 테스트를 게시 한 코드는 다음과 같아야합니다.

@RunWith(PowerMockRunner.class)
@PrepareForTest( { Random.class, ClassUsingRandom.class } ) // Don't forget to prepare the Random class! :)

public void ClassUsingRandomTest() {

    ClassUsingRandom cur;
    Random mockedRandom;

    @Before
    public void setUp() throws Exception {

        mockedRandom = PowerMockito.mock(Random.class);

        // Replaces the construction of the Random instance in your code with the mock.
        PowerMockito.whenNew(Random.class).withNoArguments().thenReturn(mockedRandom);

        cur = new ClassUsingRandom();
    }

    @Test
    public void testSwitchAtZero() {

        PowerMockito.doReturn(0).when(mockedRandom).nextInt(10);

        cur.doSomething();

        // Verify behaviour at case 0
     }

    @Test
    public void testSwitchAtOne() {

        PowerMockito.doReturn(1).when(mockedRandom).nextInt(10);

        cur.doSomething();

        // Verify behaviour at case 1
     }

    (...)

스위치에서 사례를 더 추가하려는 경우 다음 매개 변수를 수신하기 위해 nextInt (int) 호출을 스텁 할 수도 있습니다.

PowerMockito.doReturn(0).when(mockedRandom).nextInt(Mockito.anyInt());

예쁘지 않나요? :)


2

QuickCheck를 사용하십시오 ! 나는 최근에 이것을 가지고 놀기 시작했고 놀랍습니다. 대부분의 멋진 아이디어와 마찬가지로 Haskell에서 나온 것이지만 기본 아이디어는 미리 준비된 테스트 케이스를 제공하는 대신 난수 생성기가 대신 빌드 할 수 있다는 것입니다. 그렇게하면 xUnit에서 나타날 수있는 4-6 개의 경우 대신 컴퓨터에서 수백 또는 수천 개의 입력을 시도하고 설정 한 규칙에 맞지 않는 입력을 확인할 수 있습니다.

또한 QuickCheck는 실패 사례를 발견 할 때 실패하여 가장 간단한 사례를 찾을 수 있도록 단순화하려고 시도합니다. (물론 실패한 사례를 찾으면 xUnit 테스트로 빌드 할 수도 있습니다)

Java에는 두 가지 이상의 버전이 있으므로 문제가 없어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.