1

I am facing a scenario where I have to mock a certain method only when it is being invoked from very specific method. For example here is the sample code:

public class TestMethod {
    public boolean testMethod() {
        return false;
    }
}

public class ClassToBeTested {
    private TestMethod testMethod;

    public ClassToBeTested() {
        testMethod = new TestMethod();
    }
    public boolean evaluateSomething() {
        boolean evaluation1Ans = evaluate1();
        boolean evaluation2Ans = evaluate2();
        return !evaluation1Ans && evaluation2Ans;
    }

    public boolean evaluate1() {
        boolean expr = testMethod.testMethod();
        return expr;
    }

    public boolean evaluate2() {
        return testMethod.testMethod() && evaluateBooleanExpression();
    }

    private boolean evaluateBooleanExpression() {
        return true;
    }
}

public class MockitoExperiement {
    @Test
    public void testEvaluateSomething() throws Exception {
        ClassToBeTested classToBeTested = new ClassToBeTested();
        TestMethod testMethod = mock(TestMethod.class);
        when(testMethod.testMethod()).thenAnswer((Answer<Boolean>) invocationOnMock -> {
            if(new Object() {}
                    .getClass()
                    .getEnclosingMethod()
                    .getName().equals("evaluate2")) return true;
            else
                return false;
        });

        boolean flag = classToBeTested.evaluateSomething();
        System.out.print("");
    }
}

Here despite doing conditional mocking I am still receiving false from the method to be invoked. Where I am making a mistake in this sample?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
faster_fene
  • 43
  • 1
  • 11
  • Does this answer your question? [getEnclosingMethod() returning Null](https://stackoverflow.com/questions/70767101/getenclosingmethod-returning-null) – Tim Moore Dec 30 '22 at 06:50
  • Or maybe this is a better answer https://stackoverflow.com/a/442773/29470 – Tim Moore Dec 30 '22 at 06:53
  • 1
    In short, `Class.getEnclosingMethod` has nothing to do with the call stack. It tells you where the anonymous class is _defined_ (in this case, the lambda passed to `thenAnswer`). – Tim Moore Dec 30 '22 at 06:58
  • One of the problems and a partial solution: [Why is my class not calling my mocked methods in unit test?](https://stackoverflow.com/q/74027324/112968) (but not an exact dupe) – knittl Dec 30 '22 at 07:37

1 Answers1

0

You are not actually using the mock that you have created. You are still calling the testMethod method on the original testMethod object that is created in the ClassToBeTested constructor.

To use the mock that you have created, you need to inject it into the ClassToBeTested object and use it instead of the original testMethod object. You can do this by adding a setter method for the testMethod field in the ClassToBeTested class, and then using this setter to set the mock as the testMethod object before calling the evaluateSomething method.

Updated code below:

public class ClassToBeTested {
    private TestMethod testMethod;

    public ClassToBeTested() {
        testMethod = new TestMethod();
    }

    public void setTestMethod(TestMethod testMethod) {
        this.testMethod = testMethod;
    }

    public boolean evaluateSomething() {
        boolean evaluation1Ans = evaluate1();
        boolean evaluation2Ans = evaluate2();
        return !evaluation1Ans && evaluation2Ans;
    }

    public boolean evaluate1() {
        boolean expr = testMethod.testMethod();
        return expr;
    }

    public boolean evaluate2() {
        return testMethod.testMethod() && evaluateBooleanExpression();
    }

    private boolean evaluateBooleanExpression() {
        return true;
    }
}

public class MockitoExperiment {
    @Test
    public void testEvaluateSomething() throws Exception {
        ClassToBeTested classToBeTested = new ClassToBeTested();
        TestMethod testMethod = mock(TestMethod.class);
        when(testMethod.testMethod()).thenAnswer((Answer<Boolean>) invocationOnMock -> {
            if (new Object() {
            }
                    .getClass()
                    .getEnclosingMethod()
                    .getName().equals("evaluate2")) return true;
            else
                return false;
        });

        classToBeTested.setTestMethod(testMethod);//setting the object here
        boolean flag = classToBeTested.evaluateSomething();
        System.out.print("");
    }
}
Saif Ahmad
  • 1,118
  • 1
  • 8
  • 24