Activity: Logic coverage for source code

(no submission)

Purpose: Practice applying logic-based testing for program source code; get ready to work on homework assignment, and prepare for quiz 4 and the final exam

You may make a copy of a worksheet and complete this activity, or type your answers in any text editor.

You may work alone or with at most two other students in this course.


Consider an implementation of the old engineering joke: Good, Fast, Cheap.

public final class GoodFastCheap 
{
   boolean good  = false;
   boolean fast  = false;
   boolean cheap = false;

   public void makeGood () 
   {
      good = true;
      if (fast && cheap)   { cheap = false; }
   }

   public void makeFast () 
   {
      fast = true; 
      if (good && cheap)   { good = false; }
   }

   public void makeCheap () 
   {
      cheap = true;
      if (fast && good)   { fast = false; }
   }

   public void makeBad ()         { good = false; }
   public void makeSlow ()        { fast = false; }
   public void makeExpensive ()   { cheap = false; }

   public boolean isSatisfactory() 
   {
      if ((good && fast) || (good && cheap) || (fast && cheap)) 
          return true;
       
      return false;
   }

   public static void main(String[] args) 
   {
      // Question:  How well do the following tests exercise the clauses?

      GoodFastCheap gfc = new GoodFastCheap();     // g f c
                           gfc.isSatisfactory();   // F F F
      gfc.makeGood();      gfc.isSatisfactory();   // T F F
      gfc.makeFast();      gfc.isSatisfactory();   // T T F
      gfc.makeCheap();     gfc.isSatisfactory();   // T F T
      gfc.makeSlow();      gfc.isSatisfactory();   // T F T
   }
}   

Focus on the predicate in isSatisfactory(). We will start with the truth table. (Note: in reality, if tools are available, use the tools. For practice purposes and to help you prepare for the exam: we will fill the truth table ourselves)

Row# g f c P Pg Pf Pc
1 T T T T      
2 T T   T T T  
3 T   T T T   T
4 T         T T
5   T T T   T T
6   T     T   T
7     T   T T  
8              

  1. List at least one possible test pair that satisfies Predicate Coverage (PC)
    Possible answer: (2, 4)  -- predicate = T and predicate = F  
  2. List at least one possible test pair that satisfies Clause Coverage (CC)
    Possible answer: (3, 6)  -- (for each) clause = T and clause = F 
  3. List all possible test pairs that satisfy Correlated Active Clause Coverage (CACC), and then assemble the result into a CACC-adequate test set for all clauses
    Major clause        set of possible tests
         g                 (2,6), (2,7), (3,6), (3,7)
         f                 (2,4), (2,7), (5,4), (5,7)
         c                 (3,4), (3,6), (5,4), (5,6)   
         
    Assume we picked (2,6), (2,4), (3,4)     
    CACC-adequate test set = { 2,3,4,6 } 
  4. List all possible test pairs that satisfy Restricted Active Clause Coverage (RACC), and then assemble the result into a RACC-adequate test set for all clauses
     Major clause        set of possible tests
         g                 (2,6), (3,7)
         f                 (2,4), (5,7)
         c                 (3,4), (5,6)   
    
    Assume we picked (2,6), (2,4), (3,4)     
    RACC-adequate test set = { 2,3,4,6 } 
  5. At least 4 tests are needed for a RACC-adequate test. Why?
    To satisfy RACC, we first list all possible tests for each clause. 
    Then, based on the possible tests, select the smallest combination pairs (one for each clause).
       
    There are various ways to achieve RACC with exactly four tests. 
    This exercise selects the following pairs, resulting in the minimal test set that satisfies 
    RACC (i.e., RACC-adequate test)
       
    Major clause g: (2, 6)
                 f: (2, 4)
                 c: (3, 4)
    Therefore, we need 4 tests (i.e., test inputs) -- rows 2, 3, 4, and 6.  
  6. What are the possible assertions for the JUnit tests (for the RACC-adequate test)?
    Answer: [ref: https://cs.gmu.edu/~offutt/softwaretest/java/GoodFastCheapRACC.java]
    public class GoodFastCheapRACC 
    {
       // This test set achieves RACC on the predicate in the isSatisfactory() method 
       // inside the GoodFastCheap class. All other predicates in GoodFastCheap are ignored
       // by this test set. The tests in this JUnit implement one of the possibilities, 
       // namely, tests 2, 3, 4, 6. Hence, the tests here are named  
       // reach2(), reach3(), reach4(), and reach6().
    
       GoodFastCheap gfc;
    
       @BeforeEach 
       public void setUp() 
       { 
           gfc = new GoodFastCheap();    // 8:  F F F
       }
    
       @Test 
       public void test2() throws Exception 
       { 
          gfc.makeGood();                // 4: T F F
          gfc.makeFast();                // 2: T T F
          assertTrue(gfc.isSatisfactory());
       }
    
       @Test 
       public void test3() throws Exception 
       { 
          gfc.makeGood();                // 4: T F F
          gfc.makeCheap();               // 3: T F T
          assertTrue(gfc.isSatisfactory());
       }
    
       @Test 
       public void test4() throws Exception 
       { 
          gfc.makeGood();                // 4: T F F
          assertFalse(gfc.isSatisfactory());
       }
    
       @Test 
       public void test6() throws Exception 
       { 
          gfc.makeFast();               // 6: F T F
          assertFalse(gfc.isSatisfactory());
       }
    }   
  7. Does the given sequence in the main() method achieve RACC?
       No, it covers rows 2, 3, and 4. 
       To achieve RACC with exactly 4 tests, we need to add either row 6 or 7  
  8. What happens if we refactor the predicate in isSatisfactory()
    public boolean isSatisfactory() 
    {
       if (good && fast)   return true;
       if (good && cheap)  return true;
       if (fast && cheap)  return true;
           
       return false;
    }  
    The RACC tests from the original method do not satisfy RACC on the refactored method. 
    To identify what is missing (and add the missing tests to the JUnit tests 
    from the previous question), the key is to analyze reachability. 
       
    RACC tests on the refactored code require tests 2, 3, 4, 5, 6, and 7.  
       
    For the third predicate, fast && cheap
       RACC requires test xTT, xTF, and xFT, where x is a "don't know/care" value for the variable good. 
       However, these "don't know/care" values must all be false: FTT, FTF, and FFT. 
       Otherwise, the third predicate is not reached. 
       In terms of the numbering, this means that tests (rows) 5, 6, and 7 are required.
          
    For the second predicate, good && cheap
       RACC requires test TxT, TxF, and FxT, where x is a "don't know/care" value for the variable fast. 
       The first one must be TFT (or test 3), since TTT is impossible to achieve (that's a joke!).
       The second one must be TFF (or test 4), since otherwise this predicate is not reached.  
       The last one we already have from the third predicate (above) and therefore, 
       either FTT (test 5) or FFT (test 7).       
          
    For the first predicate, good && fast
       RACC requires test TTx, TFx, and FTx, where x is a "don't know/care" value for the variable cheap.
       The first one must be TTF (or test 2), since TTT is impossible. 
       The second one can be either TFF (test 4) or TFT (test 3), both of which we already have 
       from the prior analysis. 
       The last one can be either FTF (test 6) or FTT (test 5), both of which we already have 
       from prior analysis. 
           
    Therefore, we need all tests except for 1 and 8. 
    If the RACC tests in the previous question are given (namely 2, 3, 4, and 6), 
    then tests 5 and 7 are missing.  



Copyright © 2025 Upsorn Praphamontripong
Released under the Creative Commons License CC-BY-NC-SA 4.0 license.
Last updated 2025-10-25 16:34