简体   繁体   中英

Is there a way for a JUnit test to pass iff method implementation is correct AND recursive?

I am setting up some practical exams and require implementation of certain methods to be recursive. Is there a way for the JUnit test to pass only if the implementation of the method is recursive (and correct, of course)?

I have tried using getStackTrace() but I couldn't find a way to get the methods calls made earlier in the program. (Because if I can do that, I can check if containsDigit in the following example is being called the required number of times)

MWP

import static org.junit.Assert.*;
import org.junit.*;
import java.io.*;
import java.text.*;
import java.util.*;
import org.junit.rules.*;
import java.lang.reflect.*;

public class Service { //begin class 
    /**
     * @param n: assumed to be more than 0
     * @param d, d >= 0 and d <= 9
     * @return true if number n contains the digit d, false otherwise
     * you may assume that 0 itself doesn't contain ANY digit (not even 0)
     * NOTE: This method must be implemented recursively.
     * hint: n%10 gives the last digit, n/10 gives the rest of the number
     */
    public static boolean containsDigit(int n, int d) {
        return false; //to be completed
    }

    @Test
    public void testContainsDigit() {
        assertTrue(Service.containsDigit(1729, 1));
        assertTrue(Service.containsDigit(1234567890, 2));
        assertFalse(Service.containsDigit(1729, 8));
    }
}

I would like the test to pass for a recursive implementation like:

    public static boolean containsDigit(int n, int d) {
        if(n == 0) 
            return false;
        if(n%10 == d)
            return true;
        return containsDigit(n/10, d);
    }

and fail for an iterative (even if correct) implementation like:

    public static boolean containsDigit(int n, int d) {
        while(n > 0) {
            if(n%10 == d) {
                return true;
            }
            n/=10;
        }
        return false;
    }

Any help, or guidance in the right direction would very much be appreciated.

JUnit itself doesn't have tools to check whether the flow is recursive or iterative, but it can certainly check that the call returns correct results.

Now its also impossible to gather stacktraces from "earlier" executions.

I don't see how mocks can help you here neither, but I might be missing something, maybe our colleagues will provide an example for this, however I suggest the following approach:

  • Don't require method to be static, instead require the methods to be regular.

Then use the following trick:

Prepare the following class but don't provide it to the students (I've assumed that this is for educational purposes since you've talked about exams, sorry if I'm wrong) who are expected to implement the "Service" class:

 class MyServiceForChecks extends Service {
      private List<StackTraceElement[]> invocationStackTraces = new ArrayList<>(); 

      public boolean containsDigit(int n, int d) { // its not static anymore
           StackTraceElement [] stackTrace =  getStackTrace();
           invocationStackTraces.add(stackTrace); 
        return super.containsDigit(n,d);
      }

      public List<StackTraceElement[]> getInvocationStackTraces () {
           return this.invocationStackTraces;
      }
 }

In JUnit test the MyServiceForChecks class instead of Service class. After the containsDigits method finishes the execution you can call getInvocationStackTraces method and analyze the result.

If you have cannot create MyServiceForChecks class, you can generate it dynamically with CGLIB library.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM