Skip to content

Latest commit

 

History

History
1126 lines (889 loc) · 41.6 KB

README.md

File metadata and controls

1126 lines (889 loc) · 41.6 KB

유닛 테스트의 구성요소

요구사항 구성요소

Java 프로그램 유닛 테스트는 일반적으로 다음 6개의 요구사항을 각각 독립적으로 만족 해야 하므로, 각 요구사항 속성에 따라(R1-R6)를 구별할 수 있다.

  • R1: 사용자가 지시한 테스트 케이스가 실행되어야 함
  • R2: 상이한 환경에서도 동일한 테스트 코드는 동일한 테스트 케이스를 실행해야 함
  • R3: 유닛 테스트 코드의 실행은 상호 간 영향을 받지 않아야 함
  • R4: 실행 결과가 올바르지 않은 경우, 테스트 실패(test fail)로 관찰되어야 함
  • R5: 테스트 실행 결과가 올바른 경우, 테스트 성공(test pass)로 관찰되어야 함
  • R6: 테스트 결과가 사용자에게 올바르게 전달되어야 함.

실행과정 구성요소

유닛 테스트 케이스의 각 실행과정은 다음의 7가지 종류로 구분하여 범주(S1-S7)로 정의할 수 있다.

  • S1 (사용자 입력에 따른 유닛 테스트 구동): 테스트 프레임워크를 통하거나 사용자의 직접 조작을 통해 주어지는 명령을 해석하여, 실행해야 할 유닛 테스트 코드를 지정하여 시행
  • S2 (테스트 실행환경 설정): 유닛 테스트의 실행을 통제하기 위해 검증대상 모듈의 실행에 영향을 줄 수 있는 여러 변수(환경변수, 공유 변수 등)를 특정 값으로 설정
  • S3 (테스트 입력 지정): 테스트케이스의 검증 목적에 따라 조정한 테스트 입력 값을 지정
  • S4 (검증대상 모듈 실행): 지정된 테스트 입력 값으로 검증대상 모듈의 기능을 실행
  • S5 (테스트 실행 결과 검사): 실행 결과를 테스트 입력 값에 대한 기대 값과 비교하여 테스트 통과 유무를 판별
  • S6 (테스트 실행환경 설정 해제): S2에서 설정한 실행환경을 해제
  • S7 (사용자에게 테스트 결과 보고): 테스트 통과 유무를 테스트 프레임워크를 통하거나 혹은 직접 사용자에게 전달

코드 구성요소

유닛 테스트 코드는 다음과 같이 서로 다른 구조로 구성되므로, 각 코드 요소는 연관된 코드 부위에 따라 4가지 코드 구성요소(P1-P4)로 분류할 수 있다.

  • P1: 테스트케이스 별로 고유 시나리오를 정의하는 부위
  • P2: 연관된 테스트케이스를 아울러 하나의 테스트 스위트를 구성하기 위한 부위
  • P3: 검증대상 모듈이 호출하는 테스트 모형을 정의하거나, 테스트 모형 프레임워크와의 인터페이스 부위
  • P4: 테스팅 프레임워크 인터페이스 부위로, 테스트 프레임워크의 기능을 호출/참조하는 부위

Test Code Bug Patterns

1. JUnit3 에서 TestCase 클래스에 test method 가 없는 경우

  • 구성 요소 : R1, S1, P1
  • 예제 코드
import junit.framework.TestCase;

public class AssertMethodInvokedFromRunMethod extends TestCase {
public void testComplex() {
    new Thread() {
        @Override
        public void run() {
            assertTrue(true); // Appears to pass test
            assertTrue(false); // AssertMethodFailedError occurs not test failure
        }
    }.start();
}
}

2. JUnit3 에서 suite() 선언이 잘못된 경우

  • 구성 요소 : R1, S1, P2
  • 예제 코드
public class BadSuiteMethod extends TestCase {
    static Test suite() {
        TestSuite suite = new TestSuite();
        suite.addTest(new MyTests("testEquals"));
        suite.addTest(new MyTests("testNotEquals"));
        return suite;
    }
}

3. JUnit4 에서 suite()를 오버라이드한 경우

  • 구성 요소 : R1, S1, P2
  • 예제 코드
import junit.framework.TestCase;

public class BadStaticSuite extends TestCase{
    public void suite() {}         // oops, should be static
}
  • 설명 : JUnit3 프레임워크는 suite() method를 사용하여 test suite를 구성하는데, JUnit4에서는 @RunWith(Suite.class) annotation을 사용하여야 한다.

  • 출처

4. JMock 객체를 사용하면서 동시에, 해당 Test Class 에서 JMock Runner를 사용하지 않음

  • 구성 요소 : R1, S1, P4
  • 예제 코드
17 // @RunWith(JMock.class) code using Mockery Class without JMock.class
18 public class PricingServiceTests {
19
20     private static final String SKU = "3283947";
21     private static final String BAD_SKU = "-9999993434";
22
23     private PricingService systemUnderTest;
24     private DataAccess mockedDependency;
25     private Mockery mockingContext;
26
27     @Before
28     public void doBeforeEachTestCase() {
29         mockingContext = new JUnit4Mockery();
30         systemUnderTest = new PricingServiceImpl();
31         mockedDependency = mockingContext.mock(DataAccess.class);
32         systemUnderTest.setDataAccess(mockedDependency);
33     }

5. JUnit3 에서 setUp()이 오버라이드되어 있으나, super.setUp() 을 호출하지 않음

  • 구성 요소 : R1, S2, P3
  • 예제 코드
public class BadSetUp extends TestCase {

  protected void setUp() throws Exception {
    // somePreparations();
  }
  ...
}
public class CorrectSetUp extends TestCase {
  protected void setUp() throws Exception {
    super.setUp();
    // somePreparations();
  }
  ...
}

6. JUnit4 에서 setUp()을 정의하고 @Before Annotation이 없는 경우

  • 구성 요소 : R1, S2, P4
  • 설명 : JUnit4 에서는 @Before Annotation을 사용하여 테스트가 실행되기 전에 실행되는 메소드를 정의한다.
  • 예제 코드
public class BadTest {
    public void setUp() {
        bad();    
    }
}
public class GoodTest {
    @Before
    public void setUp() {
        good();
    }
}

7. JUnit4 의 @AfterClass나 @BeforeClass annotation을 사용하면서 method가 static이 아닌 경우

  • 구성 요소 : R1, S2, P4
  • 예제 코드
public class JUnit4ClassAnnotationNonStaticPositiveCases {
  @BeforeClass
  public void beforeClassSetUp() {
      setUpSomething();
  }

  @AfterClass
  public void afterClassTearDown() {
      releaseSomething();
  }
}

8. JUnit3 에서 약속된 메소드 명이 잘못된 경우

  • 구성 요소 : R1, S2, S6, P1
  • 예제 코드
import junit.framework.TestCase;

public class JUnit3TestNotRunPositiveCases extends TestCase {
  //  TestCase를 extend하나, @Test annotation을 사용하고 있어,
  //  JUnit3을 구현한 것인지, JUnit4 을 구현한 것인지 불분명하다.
  @Test
  public void testName() {}
}
  • 설명 : JUnit3 에서는 반드시 test* 형식으로 메소드 명이 정의되어야 하는데, 이를 지키지 않는 경우, 테스트가 실행되지 않는다.
  • 출처

9. JDK9 로 테스트 코드를 컴파일했을 때 오류가 나는 Mockito code pattern 을 사용한 경우

  • 구성 요소 : R1, S3, P1
  • 예제 코드
class Foo {
  <T> T getFirst(Iterable<T> xs) {
    return xs.iterator().next();
  }
}
class Test {
  @Mock Foo f;

  @Test
  public void test() {
    Iterable<Boolean> it = Arrays.asList(false);
    when(f.getFirst(it)).thenReturn(false);
  }
}
  • 설명 : Jdk9으로 해당 테스트 코드를 컴파일 하는 경우 성공해야할 test가 ClassCastException이 발생하게 되어 fail하게 된다.
  • 출처

10. JUnit3 에서 tearDown()이 오버라이드되어 있으나, super.tearDown() 을 호출하지 않음

  • 구성 요소 : R1, S6, P3
  • 설명 : JUnit3 에서 setUp() method를 오버라이드할 때 반드시, super.tearDown()을 호출하여야 한다.
  • 예제 코드
public class BadTearDown extends TestCase {
    protected void tearDown() throws Exception {
        // no super.tearDown();
    }
}
public class CorrectTearDown extends TestCase {
    protected void tearDown() throws Exception {
        super.teraDown();
    }
}

11. JUnit4 에서 tearDown()을 정의하고 @After Annotation 이 없는 경우

  • 구성 요소 : R1, S6, P4
  • 예제 코드
public class MyTest {
    public void tearDown() {
        bad();
    }
}
public class MyTest2 {
    @After 
    public void tearDown() {
        good();
    }
}

12. assertThrows에 넘겨진 코드에서 Exception을 throw한 이후 statement가 남아있음

  • 구성 요소 : R2, S4, P1
  • 예제 코드
ImmutableList xs;
assertThrows( UnsupportedOperationException.class, () -> 
    { xs = ImmutableList.of(); // the test passes if this throws 
      xs.add(0); // this is never executed 
});
assertThat(xs).isEmpty();
  • 설명 : assertThrows에 파라미터로 넘겨진 lambda에 한개 이상의 statement가 있고, 내부에서 exception을 throw한다면 그 뒤의 statement들은 무시된다.
  • 출처

13. Test Method 내부에서 Assertion 메소드의 호출이 없는 경우

  • 구성 요소 : R4, S5, P1
  • 예제 코드
public class Foo extends TestCase {
   public void testSomething() {
   Bar b = findBar();
   // This is better than having a NullPointerException
   // assertNotNull("bar not found", b);
   b.work();
   }
}

14. assertNull() 안에 boxed primitive 가 파라미터로 넘겨지는 경우

  • 구성 요소 : R4, S5, P1
  • 코드 예제
public class ImpossibleNullTest {
    @Test
    public void impossibleNullTest() {
        Integer autoboxedInt = 30;
        assertNotNull(autoboxedInt);
    }
}

15. Test Framework를 사용하는 동시에 assert()를 사용하는 경우

  • 구성 요소 : R4, S5, P1
  • 예제 코드
public class AssertUsedTest {
    @Test
    public void assertUsedTest() {
        Integer actual = methodReturnsNonZeroNumber();
        assert(actual != 0); // This is BAD
        assertNotEquals(actual, 0); // This is GOOD
    }
}

16. Assertion method 에서 동일한 객체의 reference 가 서로 같은 지 확인하는 경우

  • 구성 요소 : R4, S5, P1
  • 예제 코드
public class JUnitAssertSameCheckPositiveCase {

  public void test(Object obj) {
    // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit
    org.junit.Assert.assertSame(obj, obj);

    // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit
    org.junit.Assert.assertSame("message", obj, obj);

    // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit
    junit.framework.Assert.assertSame(obj, obj);

    // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit
    junit.framework.Assert.assertSame("message", obj, obj);
  }
}

17. Mockito 를 사용하는 테스트에서 verify 메소드를 사용하지 않음

  • 구성 요소 : R4, S5, P1
  • 예제 코드
// Calls to Mockito.when should always be accompanied by a call to a method like thenReturn.
when(mock.get()).thenReturn(answer); // correct
when(mock.get())                     // oops!
  • 설명 : Mockito를 사용하는 테스트에서 verify 메소드를 사용하지 않아, 테스트가 항상 성공하게 된다.
  • 출처 :

18. Assertion 메소드를 사용하여 동일한 객체에 대해 equality 를 검증하는 경우

  • 구성 요소 : R4, S5, P1
  • 예제 코드
public class TruthSelfEqualsPositiveCases {
  public void testAssertThatEq() {
    String test = Boolean.TRUE.toString();
    // BUG: Diagnostic contains: new EqualsTester().addEqualityGroup(test).testEquals()
    assertThat(test).isEqualTo(test);
  }
  ...
}

19. Thread.run() 내부에 assertion 이 있는 경우

  • 구성 요소 : R4, S7, P1
  • 예제 코드
public class AssertMehtodInvodedFromeRunMethod extends TestCase {
  public void testComplex() {
    new Thread() {
      @Override
      public void run() {
        assertTrue(true); // Appears to pass test
        assertTrue(false); // AssertMethodFailedError occurs not test failure
      }
    }.start();
  }
}

20. Assertion 메소드에서 test 하고자 하는 객체가 상수인 경우

  • 구성 요소 : R4, R5, S5, P1
  • 예제 코드
import static com.google.common.truth.Truth.assertThat;
public class TruthConstantAssertsPositiveCases {
  public void testAssertThat() {
    // BUG: Diagnostic contains: assertThat(new TruthConstantAssertsPositiveCases()).isEqualTo(1);
    assertThat(1).isEqualTo(new TruthConstantAssertsPositiveCases());

    // BUG: Diagnostic contains: assertThat(someStaticMethod()).isEqualTo("my string");
    assertThat("my string").isEqualTo(someStaticMethod());
    ...
}

설명 : JUnit의 assertEquals는 파라미터로 기대하는 값(상수)을 먼저, 실제 테스트 하고자 하는 값을 다음에 받아야 한다.

21. assert 구문에서 타입이 다른 두 객체의 equality 를 비교하는 경우

  • 구성 요소 : R4, R6, S5, P1
  • 예제 코드
public class TruthIncompatibleTypePositiveCase  {
  assertThat(someMethodThatReturnsString()).isEqualTo(10);
}

22. assertionEquals()에서 부동 소수점 비교에서 오차 허용 범위가 없는 경우

  • 구성 요소 : R5, S5, P1
  • 예제 코드
import junit.framework.TestCase;

public class JUnit3FloatingPointComparisonWithoutDeltaCases extends TestCase {
  public void testFloat() {
      float actual = 0.5 + 0.5;
      assertEquals(1.0f, actual); // this is not good
  }
}

23. Try 블록 내부에서 fail()이 있으나, catch 블록에서 AssertionError 를 catch 하는 경우

  • 구성요소 : R5, S5, P1
  • 예제 코드
try {
  doSomething();
  fail("expected doSomething to throw AssertionError");
} catch (AssertionError expected) {
  // expected exception
}
  • 설명 : Exception throw 되기를 기대하는 try block 안에서 실제로 Exception이 throw 되지 않아 테스트가 실패되야 하므로 fail()을 호출되었으나, catch block에서 AssertionError catch하는 경우, 테스트가 fail하지 않게 된다.
  • 출처

24. assertTrue() 내부의 판별식에서 equals 를 호출하여 두 객체가 같음을 확인하는 경우

  • 구성 요소 : R6, S5, P1
  • 예제 코드
import org.testng.Assert;
import org.testng.annotations.Test;

public class TestHelloWorld {
    @Test()
    public void testUseAssertEquals() {
        Object actual = getActual();
        Object expected = getExpected;
        Assert.assertTrue(expected.equals(actual)); // This is Bad
        Assert.assertEquals(expected,actual); // This is Good
    }
}

25. assertTrue() 내부의 판별식에서 test 하고자 하는 객체가 null 인지를 확인하는 경우

  • 구성 요소 : R6, S5, P1
  • 예제 코드
import org.testng.Assert;
import org.testng.annotations.Test;

public class TestHelloWorld {
    @Test()
    public void testUseAssertNull() {
        Object actual = getActual();
        Assert.assertEquals(actual == null ); // This is Bad
        Assert.assertNull(actual) // This is Good
    }
}

26. JUnit4 에서 test method 에 @Test Annotation이 없는 경우

  • 구성 요소 : R1, S1, P4
  • 예제 코드
public class MyTest {
  public void testBad() {
    doSomething(); // no execution of test
  }

  @Test
  public void testGood() {
    doSomething();
  }
}

27. assertionTrue() 의 파라미터로 넘겨야할 expression을 잘못 입력함

  • 구성 요소 : R1, S5, P1
  • 예제 코드
   public class SystemPrivilegesPermissionTest extends BaseTestCase {
     private void assertEquivalentPermissions(Permission p1, Permission p2) {
       ...
       assertEquals(p1.hashCode(), p2.hashCode());
       assertTrue(p1.implies(p2));
-      assertTrue(p1.implies(p2));
+      assertTrue(p2.implies(p1));
    }
  }
  • 설명 : Check both "p1 implies p2" and "p2 implies p1" in assertEquivalentPermissions(), instead of checking "p1 implies p2" twice.
  • 출처

28. xml query로 사용되는 변수의 값을 잘못 입력함

  • 구성 요소 : R1, S2, P1
  • 예제 코드
  pupblic class PredicatesTests extends AbstractQueryTest {
    ...
    public void testEquality() throws RepositoryException {
-   String stmt = "/" + jcrRoot + "/*[@" + jcrPrimaryType + "='" + nodeTypeName + "']";
+   String stmt = "/" + jcrRoot + "/" + testPath + "/*[@" + jcrPrimaryType + "='" + nodeTypeName + "']";
    try {
      qm.createQuery(stmt, Query.XPATH);
    ...
  }
  
  public abstract class Abstract JCRTest extends JUnitTest {
    ...
    /***
      *  Absolute path to the test root node.
      */
    protected String testRoot;
    ...
    protected void setUp throws Exception {
      super.setUp();
      testRoot = getProperty(RepositoryStub.PROP_TESTROOT);
      if (testRoot == null) {
        fail("Property '" + RepositoryStub.PROP_TESTROOT + "' is not defined.");
      }
      ...
      
      // cut off '/' to build testPath
      testPath = testRoot.substring(1);
      ...
    }
  }  
  • 설명 : xml Query에 사용되는 stmt 변수에 testPath가 concatenate 되어야 하는데, PredicateTest class에서 이를 누락하였다. (PredicatesTest does not respect testroot configuration property)
  • 출처

28. FileInputStream 을 생성하였으나 close()를 호출하지 않음

  • 구성 요소 : R1, S6, P1
  • 예제 코드
@Test
   public void testBZip2Codec() throws IOException {
     ...
     // check the output to make sure it is what we expected.
     // read the gzip file and verify the contents
     BZip2Codec bz2Codec = new BZip2Codec();
     InputStream bz2in = bz2Codec.createInputStream(new FileInputStream(f
-        .getPath()
-        + "/sub-foo.bz2"));
+        .getPath() + "/sub-foo.bz2"));
     byte[] buf = new byte[1];
     StringBuilder output = new StringBuilder();
 
     while ((bz2in.read(buf)) > 0) {
       output.append(new String(buf));
     }
+    bz2in.close(); // Must close for windows to delete
     assertEquals(expected, output.toString());
 
     assertTrue("temp folder successfully deleted", FileUtil.rmr(f));
   }
  • 설명 : InputStream을 생성한 뒤 테스트 종료 전 close를 하지 않은 경우이다. (windows에서는 close 되지 않음)
  • 출처

29. Thread를 생성하였으나, join이 호출되지 않고 테스트가 종료됨\

  • 구성 요소 :R4, S2, S3, S6, P1
  • 코드 예제
 public simpleThread(String argv[]) throws Exception {

    ij.getPropertyArg(argv);
    _connection = ij.startJBMS();
    Connection conn = GetConnection();
    Statement stmt = conn.createStatement();
    ...
+   Thread[] threads = {
+     new simpleThread(query,0),
+     new simpleThread(query,10000),
+     new simpleThread(query,10100),
+     new simpleThread(query,20000),
+   };
+
+   for (int i = 0; i < threads.length; i++) {
+     threads[i].join();
    }
+
+   _connection.close();
+   _connection = null;
  }
  • 설명 : 테스터는 5-8 라인에서 Exception이 발생되는 것을 기대하고 있고, 발견되지 않는 경우를 test fail로 정의하였다. 10-13 라인은 새로이 추가된 부분인데, 스레드를 생성하고 나서 join()을 호출하지 않았기 때문에, 결과가 나오기도 전에 테스트가 종료되어 버리게 되는 경우이다.

  • 출처

30. org.junit.Test 를 import 하는 java 파일의 public class 명이 Test 로 시작되지 않음

  • 구성 요소 : R1, R3, S1, P4
- public class SliderUtilsTest {
+ public class TestSliderUtils {
    ...
  }
  • 설명 : Maven에서 테스트명이 Test로 시작해야 Test Class로 인식한다 (Default).
  • 출처

31. Exception을 기대한 테스트케이스에서 try블락 안에 fail()의 호출이 없음

  • 구성 요소 : R1, R4, S5, P1
  • 예제 코드
/* DERBY-6088 */
    try {
      insert.setObject( 1, null, ILLEGAL_JDBC_TYPES[ i ] );
+     fail( "setObject() should have failed." );
    }
      catch (SQLException se) { assertUnimplemented( se ); }
    }
/* DERBY-3852*/
JDBCDataSource.setBeanProperty(ds, "shutdownDatabase", "shutdown");
    try {
      ds.getConnection();
+     fail("shutdown should raise exception");
    } catch (SQLException sqle) {
      assertSQLState("XJ015", sqle);
    }
  • 설명 : Exception을 의도한 테스트케이스에서 의도 하지 않은 Exception이 발생하지 않은 경우 fail()이 없어서 테스트가 해당 부분을 넘어가게 된다.

  • 출처

32. SSLContext 의 getInstance 메소드에 "SSL"을 파라미터로 넘긴 경우

  • 구성 요소 : R2, S2, S3, P1
  • 예제 코드
- SSLContext sc = SSLContext.getInstance("SSL");
+ SSLContext sc = null;
+ if (System.getProperty("java.vendor").contains("IBM")) {
+     sc = SSLContext.getInstance("SSL_TLS");
+ } else {
+     sc = SSLContext.getInstance("SSL");
+ }
  • 설명 : IBM JDK 버전에 따라서 "SSL_TLS"를 getInstance()의 파라미터로 넘겨야 한다.
  • 출처

33. file path 의 경로를 '/'으로만 구분하는 경우

  • 구성 요소 : R2, S3, P1
  • **코드 **
   private static void delete(File dir) throws IOException {
-    Path p = new Path("file://"+dir.getAbsolutePath());
     Configuration conf = new Configuration();
-    FileSystem fs = p.getFileSystem(conf);
+    FileSystem fs = FileSystem.getLocal(conf);
+    Path p = fs.makeQualified(new Path(dir.getAbsolutePath()));
     fs.delete(p, true);
   }
  • 설명 : The prior code for path construction fails on Windows due to the drive spec and backslashes. Using FileSystem#makeQualified against the local file system works cross-platform.

  • 출처

34. for 문의 조건문을 잘못 입력하여 test 를 실행하지 못한 경우

  • 구성 요소 : R2, S4, P1
  • 코드 예제
   public void testDirectoryScanner() throws Exception {
     // Run the test with and without parallel scanning
-    for (int parallelism = 1; parallelism < 2; parallelism++) {
+    for (int parallelism = 1; parallelism < 3; parallelism++) {
       runTest(parallelism);
     }
   }
  • 설명 : for문안의 조건문을 잘못 입력하여 test가 실행되지 않았다.
  • 출처

35. 파일을 생성한 뒤 try-catch 블록 이후 finally 블록에 close()를 호출하지 않은 경우

  • 구성 요소 : R2, S6, P1

  • 코드 예제

  public void testSessionGetcontentHandler() throws RepositoryException, IOException, SAXException {
    FileInputSstrean in = new FileInputStream(file);
-   exportRepository(SAVEBINARY, RECURSE);
-   doImportNoSave(treeComparator.targetFoler, in, CONTENTHANDLER);
+   try {
+     exportRepository(SAVEBINARY, RECURSE);
+     doImportNoSave(treeComparator.targetFoler, in, CONTENTHANDLER);    
+   } finally {
+     in.close();
+ }
  • 설명 : FileInputStream을 생성한 뒤 테스트가 끝나기 전 try블락 안에 exception이 throw될 수 있는 메서드를 사용한 이후, finally 블록 안에 FileInputStream의 close()를 호출하지 않은 경우이다. 이경우 파일이 생성된 뒤에 temporary files created by some jUnit test are not automatically removed

  • 출처

36. Test Suite 에서 하나의 DB 를 사용하고, Sequence 를 생성한 뒤 Drop 하지 않은 경우

  • 구성 요소 : R3, S2, S5, P2

  • 설명 : ‘alpha_seq’ 라는 sequence가 만들어지고 testCase가 종료되기 전 drop 되지 않아, 다음 테스트의 실행에 영향을 미친다. lang.SequenceTest fails w/ "Seqeunce 'ALPHA_SEQ' already exists." on phoneME/cvm. commit message : Do cleanup in testcases to make the testcases independent of running order.

  • 코드 설명

  public class SequenceTest extends BaseJDBCTestCase {
    public static Test suite() {
      public void testCreateOtherSchemeSequence() throws SQLExecption {
        ..
        assertStatementError("42507", stmtBeta, "CREATE SEQUENCE alpha.alpha_seq3");
 
+       // Cleanup:
+       stmtAlpha.executeUpdate("DROP SEQUENCE alpha_seq");
+        
        stmtAlpha.close();

37. Socket 을 생성하고 테스트가 끝나는 시점에 close() 하지 않은 경우

  • 구성 요소 : R3, S6, P1
  • 코드 설명
  @Test
  public void testShortCircuitReadFromServerWithoutShm() throws Exception {
    TemporarySocketDirectory sockDir = new TemporarySocketDirectory();
    //...
        
+   sockDir.close();
  }
  • 설명 : socket을 생성하고 close를 하지 않아 다음 테스트 실행 결과에 영향을 미칠 수 있다.

  • 출처

38. 테스트 실행 도중 공유 변수의 값을 임의로 변경한 후 이를 초기 값으로 되돌리지 않음

  • 구성 요소 : R3, S6, P1, P2
  • 예제 코드
@Test
public void testGzipOutputFormat() throws IOException, InterruptedException {
    // set the output format.
    FlumeConfiguration conf = FlumeConfiguration.get();
    conf.set(FlumeConfiguration.COLLECTOR_OUTPUT_FORMAT, "syslog");
    conf.set(FlumeConfiguration.COLLECTOR_DFS_COMPRESS_GZIP, "true");
    ...
}

@Test
public void testDefaultCodec() throws IOException, InterruptedException {
    // set the output format.
    FlumeConfiguration conf = FlumeConfiguration.get();
    conf.set(FlumeConfiguration.COLLECTOR_OUTPUT_FORMAT, "syslog");
    conf.set(FlumeConfiguration.COLLECTOR_DFS_COMPRESS_CODEC, "DefaultCodec");
+   conf.set(FlumeConfiguration.COLLECTOR_DFS_COMPRESS_GZIP, "false");
    ...
}    
  • 설명 : 이전 테스트에서의 설정이 다음 테스트에서도 적용되어 테스트 결과가 바뀌는 경우이다.

  • 출처

39. Ant 1.9.3 에서 ant 가 test 결과를 file 을 수정할 수 있는 권한을 설정하지 않음

  • 구성 요소 : R3, S7, P4
  • 예제 코드
  // java/testing/org/apache/derbyTesting/functionTests/util/derby_tests.policy
  ...
+ // Starting with Ant 1.9.3, write permission has to be granted to ant.jar
+ // as well so that Ant's JUnit runner can write test results to a file.
+ // Only needed when running the tests under Ant. See DERBY-6685.
+ grant codeBase "${derbyTesting.ant}" {
+    permission java.io.FilePermission "${user.dir}${/}*", "write";
+ };
+
  • 설명 : Ant 1.9.3 버전부터 Test result를 file에 쓰기 위해 ant.jar에 write permission이 필요해졌는데 관련 권한 설정이 실행되지 않았다.
  • 출처

40. 모든 test 가 실행되는지 확인하지 않음

  • 구성 요소 : R4, S1, P4-
  • 예제 코드
public static void runTests( final SecurityEvaluator securityEvaluator, final PrefixMapping prefixMapping ) throws Exception
{
    ...
    Method lockTest = null;
    for (final Method m : pmTest.getClass().getMethods())
    {
        if (m.isAnnotationPresent(Test.class))
        {
        // lock test must come last
            if (m.getName().equals("testLock")) { lockTest = m; }
            else { pmTest.setup(); m.invoke(pmTest); }
        }
    }
+   Assert.assertNotNull( "Did not find 'testLock' method", lockTest );     
    pmTest.setup();
    lockTest.invoke(pmTest);
}
  • 설명 : 테스트를 실행시키는 부분에서 실제 의도하는대로 테스트가 실행되는지 확인하는 코드가 추가되지 않았다.

  • 출처

41. test 가 추가되기 전에 호출되어야 할 메소드 leasechecker.interruptAndJoin()이 누락됨

  • 구성 요소 : R4, S2, P1
  • 예제 코드
Index: src/test/hdfs/org/apache/hadoop/hdfs/TestReadWhileWriting.java
===================================================================
--- src/test/hdfs/org/apache/hadoop/hdfs/TestReadWhileWriting.java  (revision 889032)
+++ src/test/hdfs/org/apache/hadoop/hdfs/TestReadWhileWriting.java  (working copy)
@@ -83,6 +83,8 @@ 
       //b. On another machine M2, open file and verify that the half-block
       //   of data can be read successfully.
  01   @Test
  02   public void pipeline_02_03() throws Exception {
  03    ...
  04   checkFile(p, half, conf);
+ 05   AppendTestUtil.LOG.info("leasechecker.interruptAndJoin()");
+ 06   ((DistributedFileSystem)fs).dfs.leasechecker.interruptAndJoin();
  07   //c. On M1, append another half block of data.  Close file on M1.
  08   {
  09     //sleep to let the lease is expired.
  10     Thread.sleep(2*LEASE_LIMIT);
  11 
  12     final DistributedFileSystem dfs = (DistributedFileSystem)FileSystem.newInstance(conf);
  13     final FSDataOutputStream out = append(dfs, p);
  14     write(out, 0, half);
  15     out.close();
  16   }
  • 설명 : Test가 추가되기전에 반드시 호출되어야할 메소드가 누락되었다.

  • 출처

42. 테스트 환경을 설정하는 동일한 메소드를 연속해 중복 실행하는 경우

  • 구성 요소 : R4, S2, P1
  • 설명 : 테스트 환경을 설정하는 메소드를 연속해서 중복 호출하였다.
  • 예제 코드
   c.setInt("hbase.ipc.client.connect.max.retries", 1);
-  c.setInt("hbase.ipc.client.connect.max.retries", 1);
   c.setInt("dfs.client.block.recovery.retries", 1);

43. setup() 이나 teardown()에서 Tree의 child node들을 제거하지 않음 (설정 초기화 오류)

  • 구성 요소 : R4, S2, S6, P2
  • 예제 코드
    protected Node cleanUpTestRoot(Session s) throws RepositoryException
    ...
    // clean test root
    testRootNode = root.getNode(testPath);
    for (NodeIterator children = testRootNode.getNodes(); children.hasNext();) {
-     children.nextNode().remove();
+     Node child = children.nextNode();
+     NodeDefinition nodeDef = child.getDefinition();
+     if (!nodeDef.isMandatory() && !nodeDef.isProtected()) {
+       child.remove();
+     }
    }
  • 설명 : 테스트 환경을 초기화하는 메서드에서 적절한 환경 설정(children node의 제거)이 이루어지지 않아서, 실제 유닛의 실행과는 상관없이 테스트가 실패한다. JCR-505: TCK: AbstractJCRTest fails if setUp/tearDown cannot remove children of test node
  • 출처

44. Exception가 Throw될 수 있는 메소드를 호출하나 그것을 테스트하지 않음

  • 구성 요소 : R4, S5, P1
  • 예제 코드
   public void testGetInvalidJob() throws Exception {
-    RunningJob runJob = new JobClient(getJobConf()).getJob(JobID.forName("job_0_0"));
-    assertNull(runJob);
+    try {
+      RunningJob runJob = new JobClient(getJobConf()).getJob(JobID.forName("job_0_0"));
+      fail("Exception is expected to thrown ahead!");
+    } catch (Exception e) {
+      assertTrue(e instanceof IOException);
+      assertTrue(e.getMessage().contains("ApplicationNotFoundException"));
+    }
   }
  • 설명 : 테스트 대상 코드가 null을 리턴하는 것에서 IOException을 throw하는 것으로 변경되어 Test code도 변경되어야 하는데 변경되지 않아 Test가 실패한다.
  • 출처