2

For practicing algorithm questions, I set up my Java code like: ProblemClass.java

public static void main(String[] args) {
        Solution solution = new ProblemClass().new Solution();
        Utils.isEqual(solution.function("abc"), "def");
}
public class {
    public Solution {
        public String function(String s) {}
    }
}

The Utils.isEqual is basically wrapping a comparison like:

    public static void isEqual(Object actual, Object expected) {
        if (actual == null && expected == null || actual.equals(expected)) {
            System.out.println("Pass.");
        } else {
            System.out.println("Fail. Expecting: [" + expected + "] Actual result: [" + actual + "]");
        }
    }

When I run hundred of test cases, all I see on the command prompt is:

Pass.
Pass.
Pass.
Pass.
...
Fail. Expecting: [false] Actual result: [true]
...

I don't know what test case has failed. I want to have some indication of what test has failed. I am open to other suggestions. So far, I thought maybe there is a way to display the parameters passed into function when calling isEqual through something like Reflection. I could not find a clear answer on that.

Lastly, I want to keep everything in the main() so all my tests and code is in one place as opposed to have a unit test class that I have to manage.

return 0
  • 4,226
  • 6
  • 47
  • 72
  • 5
    You could include a "message" with the assertion. But would it not be easier to use a testing framework, such as JUnit or TestNG? – Slaw Dec 30 '20 at 00:06
  • How is this question similar to "How can I get the current stack trace in Java?" ??? – return 0 Dec 30 '20 at 16:56
  • I did not vote to close, but I would guess because if you dump the stack trace in your assertion then you can follow it to exactly which test failed. But I still recommend using a testing framework if you can. – Slaw Dec 30 '20 at 21:30

1 Answers1

2

You can not access a parameter your caller passed to another function: Method parameters are stored only while the method is still executing; once a method has completed execution, the storage that held its parameters is reclaimed and reused for other purposes (such as the parameters / local variables for the next function to execute).

Therefore you must change the structure of your code so this value is somehow passed to the function that needs it. A simple way is to add an additional parameter:

public static void assertEquals(String actual, String input, String expected) {
    if (Objects.equals(actual, expected) {
        System.out.println(input + ": pass");
    } else {
        System.out.println(input + ": failed. Expected: " + expected + ", but got " + actual);
    }
}

and calling it like:

assertEquals(solution.function("abc"), "abc", "def");

That works, but requires passing the input twice. One way to avoid that is passing the solution rather than invoking its method directly:

check(solution, "abc", "def");

where

check(Solution solution, String input, String expected) {
    String actual = solution.function(input);
    if (Objects.equals(expected, actual)) {
        System.out.println(input + ": pass");
    } else {
        System.out.println(input + ": failed. Expected: " + expected + ", but got " + actual);
    }
 }

However, that still requires check to know which method to call (function is our example). If you need check to work with arbitrary methods, you can pass the method itself rather than merely the object that defines it:

check(solution::function, "abc", "def");

where

interface TestCase {
    String func(String input);
}

void check(TestCase test, String input, String expectedOutput) {
    String output = test.func(input);
    // compare and print as before
}

All that said, in professional code you would probably be using a test framework like junit rather than reinventing the wheel.

meriton
  • 68,356
  • 14
  • 108
  • 175