Mockito cannot seem to mock slf4j interface - unit-testing

I'm trying to make a wrapper for an slf4j Logger interface and test it, but I keep getting the following error.
TestDebugLog FAILED
Wanted but not invoked:
logger.debug("some message", "arg1", "arg2");
-> at com.common.TrebuchetLoggerTest.TestDebugLog(TrebuchetLoggerTest.java:37)
However, there was exactly 1 interaction with this mock:
logger.debug("some message", "arg1", "arg2");
-> at com.common.TrebuchetLogger.debug(TrebuchetLogger.java:19)
at com.common.TrebuchetLoggerTest.TestDebugLog(TrebuchetLoggerTest.java:37)
1 test completed, 1 failed
My test looks like
#RunWith(MockitoJUnitRunner.class)
public class TrebuchetLoggerTest {
TrebuchetLogger trebuchetLogger;
#Mock TrebuchetClient trebuchetClient;
#Mock Logger logger;
#Before
public void setup() {
trebuchetClient = mock(TrebuchetClient.class);
when(trebuchetClient.launch(any(String.class))).thenReturn(true);
logger = mock(Logger.class);
trebuchetLogger = new TrebuchetLogger(trebuchetClient, logger);
}
#Test
public void TestDebugLog() {
trebuchetLogger.debug("debug-suffix", "some message", "arg1", "arg2");
verify(logger).debug("some message", "arg1", "arg2");
}
}
My code is:
package com.common;
import org.slf4j.Logger;
import lombok.NonNull;
import com.trebuchet.client.TrebuchetClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.inject.Inject;
import org.slf4j.LoggerFactory;
#RequiredArgsConstructor(onConstructor = #__(#Inject))
public class TrebuchetLogger {
#NonNull private TrebuchetClient trebuchetClient;
#NonNull private Logger log;
public void debug(String trebuchetSuffix, String format, Object... arguments) {
if (trebuchetClient.launch(trebuchetSuffix)) {
log.debug(format, arguments);
}
}
public void info(String trebuchetSuffix, String format, Object... arguments) {
if (trebuchetClient.launch(trebuchetSuffix)) {
log.info(format, arguments);
}
}
public void warn(String trebuchetSuffix, String format, Object... arguments) {
if (trebuchetClient.launch(trebuchetSuffix)) {
log.warn(format, arguments);
}
}
public void error(String trebuchetSuffix, String format, Object... arguments) {
if (trebuchetClient.launch(trebuchetSuffix)) {
log.error(format, arguments);
}
}
}
Why does my mockito mock fail with seemingly identical results in the error message?

You are calling different overloads in your SUT and verify.
// SUT
log.debug(format, arguments);
// Test
verify(logger).debug("some message", "arg1", "arg2");
correspond to overloads:
debug​(String format, Object... arguments)
debug​(String format, Object arg1, Object arg2)
If you need to call varargs-overload when you have a format and 2 arguments, you need to pass the arguments as an array.

Related

PowerMock calls real method

I am trying to spy private method with PowerMock but on the line when I define the what should be returned when the private method is called, it calls the method and I am getting and Null Pointer Exception. What PowerMock is calling real method on this line ?
myService= PowerMockito.spy(new MyService(myParam));
.....
PowerMockito.when(myService, "getCLientBy", anyString(), anyString(), anyString()).thenRetur`n(Client.of(setName, new HashSet<>())); // here it calls real method
Ensure that you prepare your class to be used in spy by adding #PrepareForTest(MyService.class)
#RunWith(PowerMockRunner.class)
// We prepare MyService for test because it's final
// or we need to mock private or static methods
#PrepareForTest(MyService.class)
public class YourTestCase {
//...
#Test
public void spyingWithPowerMock() {
MyService classUnderTest = PowerMockito.spy(new MyService(myParam));
//.....
// use PowerMockito to set up your expectation
PowerMockito.doReturn(Client.of(setName, new HashSet<>()))
.when(classUnderTest, "getClientBy", anyString(), anyString(), anyString());
//...
Also make sure provide the correct method name to be invoked.
#user1474111 and #Nkosi
I've built a small simulation of your example.
Maybe you also need to add the Client class in the PrepareForTest annotation.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ MyService.class, Client.class })
public class Example1Test {
#Test
public void testPowerMockito() throws Exception {
MyService myService = PowerMockito.spy(new MyService("myParam"));
PowerMockito.when(myService, "getClientBy", ArgumentMatchers.anyString(), ArgumentMatchers.anyString(),
ArgumentMatchers.anyString()).thenReturn(Client.of("setName", new HashSet<String>()));
myService.run();
Assert.assertEquals("setName", myService.getClient().getName());
}
}
public class MyService {
private Client client;
public MyService(String param) { }
private Client getClientBy(String a, String b, String c) {
return new Client(a + b + c);
}
public Client getClient() {
return this.client;
}
public void setClient(Client client) {
this.client = client;
}
public void run() {
setClient(getClientBy("A", "B", "C"));
}
}
public class Client {
private final String name;
public Client(String name) {
this.name = name;
}
public static Client of(String name, HashSet<String> hashSet) {
return new Client(name);
}
public String getName() {
return name;
}
}

How to get intance of InvocationContext for unit tests

I am trying to write a unit test for a method taking the InvocationContext as parameter. More specifically here's the signature and essentials of the method.
#AroundInvoke
public Object autoLogMethodCall(final InvocationContext context) throws Exception {
String className = context.getClass().getSimpleName();
String packageName = context.getClass().getPackage().getName();
String methodName = context.getMethod().getName();
// Some logging stuff that is the target of actual testing
}
As you see, it is an interceptor method I intend to use for doing some basic logging for certain method calls.
Then I have unit test which I want to test that the logged messages will be properly formatted. But the problem is that that I can not create an instance of the InvocationContext to pass as a parameter for testing.
I have tried the following mocking.
#RunWith(PowerMockRunner.class)
public class AutoLoggingTest extends TestCase {
#Test
public void testAutoLogger() {
Logger log = new MyLogger(); // This is an implementation of org.apache.logging.log4j.Logger, which will hold the generated messages to check at the test
InvocationContext mockContext = PowerMockito.mock(InvocationContext.class);
Class clazz = AutoLoggingTest.class;
// The row causing the error 'MissingMethodInvocation'
PowerMockito.when(mockContext.getClass()).thenReturn(clazz);
try {
InterceptingClass ic = new InterceptingClass();
ic.setLogger(log);
ic.autoLogMethodCall(mockContext);
MyLogger myLogger = (MyLogger) ic.getLogger();
assertEquals(2, myLogger.getMessages().size());
} catch (Exception e) {
e.printStackTrace();
fail("Should not cause an exception in any case");
}
}
// Check the actual messages based on the information given in mocked InvocationContext object
}
But it does not work.
causes:
Tests in error:
AutoLoggingTest.testAutoLogger:25 » MissingMethodInvocation.
when() requires an argument which has to be 'a method call on a mock'.).
Any advice on how to do the mocking properly?
This required some thinking out of the box. Some mixed content with the mocked InvocationContext is needed. We can provide the testing class itself in the mocked InvocationContext object, thus I added and changed the following in the test class itself:
#RunWith(PowerMockRunner.class)
public class AutoLoggingTest extends TestCase {
// This method needs to be added here to provide it for mocked InvocationContext.
public void methodForLoggingTesting() {
}
#Test
public void testAutoLogger() {
Logger log = new MyLogger();
// Some renaming & refactoring after the initial stuff
AutoLoggingUtility alu = new AutoLoggingUtilityImplForTesting();
alu.setLogger(log);
InvocationContext mockContext = PowerMockito.mock(InvocationContext.class);
try {
Method testMethod = this.getClass().getMethod("methodForLoggingTesting");
PowerMockito.when(mockContext.getMethod()).thenReturn(testMethod);
PowerMockito.when(mockContext.proceed()).thenReturn(null);
} catch (Exception e) {
e.printStackTrace();
fail("Should not throw an exception, InvocationContext mocking failed!");
}
try {
alu.autoLogMethodCall(mockContext);
} catch (Exception e) {
e.printStackTrace();
fail("Should not throw an exception, logging failed!");
}
MyLogger myLogger = (MyLogger) alu.getLogger();
assertEquals(3, myLogger.getMessages().size());
// More tests to check the actual logged content
}
}
Also I realized I should provide the code for the 'MyLogger' as it wasn't quite trivial to implement for the test.
// Logger = org.apache.logging.log4j.Logger
// ExtendedLoggerWrapper = org.apache.logging.log4j.spi.ExtendedLoggerWrapper
#SuppressWarnings("serial")
protected class MyLogger extends ExtendedLoggerWrapper implements Logger {
private List<String> messages;
public MyLogger() {
super(null, null, null);
this.clearMessages();
}
// The actual log calls need to get stored to store the messages + prevent from NullPointerExceptions
#Override
public void trace(String msg) {
messages.add(msg);
}
// The actual log calls need to get stored to store the messages + prevent from NullPointerExceptions
#Override
public Object exit(Object obj) {
messages.add("Exited with: " + obj);
return obj;
}
public List<String> getMessages() {
return this.messages;
}
public void clearMessages() {
messages = new ArrayList<>();
}
/**
* You need to override all the method calls used to prevent NullPointerExceptions.
*
* #return <code>True</code> always, as required so in test.
*/
#Override
public boolean isTraceEnabled() {
return true;
}
}
And since there was some minor refactoring needed in the original Logging class, it now looks like this:
public abstract class AutoLoggingUtility {
private static final String logEntryTemplate = "Call to: %1$s#%2$s";
private static final String logExitTemplate = "'%1$s' call duration: %2$s ms";
public AutoLoggingUtility() {
}
#AroundInvoke
public Object autoLogMethodCall(final InvocationContext context) throws Exception {
// Note the methods Overridden in MyLogger
if (this.getLogger().isTraceEnabled()) {
String methodName = null;
String className = null;
try {
Method method = context.getMethod();
methodName = method.getName();
// Contains package
className = context.getMethod().getDeclaringClass().getName();
} catch (Exception e) {
// May not crash
methodName = "?method?";
className = "?class?";
}
Object[] args1 = { className, methodName };
String logMsg = String.format(getLogentrytemplate(), args1);
this.getLogger().trace(logMsg);
long startTime = System.currentTimeMillis();
try {
return this.getLogger().exit(context.proceed());
} finally {
Object[] args2 = { methodName, System.currentTimeMillis() - startTime };
logMsg = String.format(getLogexittemplate(), args2);
this.getLogger().trace(logMsg);
}
} else {
// mocked
return context.proceed();
}
/**
* Forces each extending class to provide their own logger.
*
* #return The logger of the extending class to direct the messages to correct logging context.
*/
abstract Logger getLogger();
}
The 'AutoLoggingUtilityImplForTesting' simply extends 'AutoLoggingUtility' to hold instance of MyLogger.
Summarum:
The trick is to provide instance of the test classes method 'methodForLoggingTesting' for the mocked object to return when the 'getMethod()' is called. => No need to try to mock excess stuff.

how to mock static enum parameter using powermock

I am using powermock and meet two problems like this:
public LogUtils {
public static enum Type {
****
}
public void log(Type type, Date date) {
***
}
}
public class Service {
public int call() {
LogUtils.log(Type.T1, new Date());
***
return *;
}
}
#RunWith(PowerMockRunner.class)
public class TestService {
#Test
#PrepareForTest(LogUtils.class)
public void test() {
Service service = new Service();
PowerMockito.mockStatic(LogUtils.class);
LogUtils.log(Type.T1, new Date()); // test here, but failed.
service.
}
#Test
#PrepareForTest(LogUtils.class)
public void test2() {
Service service = new Service();
PowerMockito.mockStatic(LogUtils.class);
LogUtils.log(Type.T1, new Date());
int ret = service.call();
Assert.isTrue(1, ret);
}
}
For test1, it would throw Exception:
java.lang.VerifyError: Bad type on operand stack in arraylength
Exception Details:
Location:
LogUtilss$Type.values()[LogUtils$Type; #137: arraylength
Reason:
Invalid type: 'java/lang/Object' (current frame, stack[2])
Current Frame:
bci: #137
flags: { }
locals: { 'java/lang/Object', top, top, top, 'java/lang/Object' }
stack: { 'java/lang/Object', integer, 'java/lang/Object' }
it is caused by defining static enum in class instead of directly creating enum with single file. How to solve this problem as our codes almost define static enum in class?
For test2, if the first problem is solved, the direct call of LogUtils.log could be successfully skipped, but when call service.call(), couldn't skip.
Anyone could kindly help on this? Thanks a lot in advance.
I use powermock 1.6.5 and JDK1.7
Full code example:
public class LogUtils {
public static enum Type {
T(1),
D(2);
private int type;
Type(int type) {
type = type;
}
}
public static void log(Type t, String msg) {
System.out.println("skip this method");
}
}
public class TestAction {
public void test() {
String msg = "logMsg";
LogUtils.log(LogUtils.Type.T, msg);
}
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
public class UnitTest {
#Test
#PrepareForTest(LogUtils.class)
public void test() {
PowerMockito.mockStatic(LogUtils.class);
TestAction a = new TestAction();
LogUtils.log(LogUtils.Type.T, "test");
a.test();
}
}
Expect: no print for 'skip this method'.

Unit testing JavaFx 2 application with TestNG

I wrote a rather complex JavaFx 2 application for which I'd like to write a bunch of unit tests. Problem is when I try to conduct the tests I get a runtime error complaining about uninitialized toolkit.
From what I can tell I should somehow invoke Application.launch() in a #BeforeClass method but this causes a deadlock as Application.launch() doesn't return to calling thread.
So question is how should I initialize JavaFx?
This is the skeleton of the code that doesn't work:
public class AppTest extends Application {
#BeforeClass
public void initialize() {
launch(); //this causes a deadlock
}
#Test
public void test1() {
//conduct test here
}
#Test
public void test2() {
//conduct other test here
}
#Override
public void start(Stage arg0) throws Exception {
}
Thanks in advance!
From another question here on stackoverflow, I've made myself this little helper class:
import javafx.application.Application;
import javafx.stage.Stage;
public class JavaFXInitializer extends Application {
private static Object barrier = new Object();
#Override
public void start(Stage primaryStage) throws Exception {
synchronized(barrier) {
barrier.notify();
}
}
public static void initialize() throws InterruptedException {
Thread t = new Thread("JavaFX Init Thread") {
public void run() {
Application.launch(JavaFXInitializer.class, new String[0]);
}
};
t.setDaemon(true);
t.start();
synchronized(barrier) {
barrier.wait();
}
}
}
which can then be used easily in a #BeforeClass setup method:
#BeforeClass
public void setup() throws InterruptedException {
JavaFXInitializer.initialize();
}
The main think is to consider your tests to be run inside an FX thread. When you create a class extends Application, you create in fact a process. This is what you want to test.
So to launch some unit tests on an Application, first create an FXAppTest that extends Application and then inside FXAppTest you launch your unit test. Here is the idea.
Here is an example with JUnit. I create a Runner that launch the test inside an FXApp for test.
Here is an example of code for FxApplicationTest (we launch unit test inside it)
public class FxApplicationTest extends Application {
private volatile boolean isStopped;
#Override
public void start(final Stage stage) {
StackPane root = new StackPane();
Scene scene = new Scene(root, 10, 10);
stage.setScene(scene);
}
public void startApp() {
launch();
}
public void execute(final BlockJUnit4ClassRunner runner, final RunNotifier notifier) throws InterruptedException {
isStopped = false;
Platform.runLater(new Runnable() {
#Override
public void run() {
runner.run(notifier);
isStopped = true;
}
});
while (!isStopped) {
Thread.sleep(100);
}
}
And the Runner :
import org.apache.log4j.Logger;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
public class JUnitFxRunner extends Runner {
private final BlockJUnit4ClassRunner runner;
private final Logger LOGGER = Logger.getLogger(JUnitFxRunner.class);
public JUnitFxRunner(final Class<?> klass) throws InitializationError {
super();
runner = new BlockJUnit4ClassRunner(klass);
}
#Override
public Description getDescription() {
return Description.EMPTY;
}
#Override
public void run(final RunNotifier notifier) {
try {
final FxApplicationTest fxApplicationTest = new FxApplicationTest();
MyTestRunner runnable = new MyTestRunner(runner, notifier, fxApplicationTest);
new Thread(runnable).start();
Thread.sleep(100);
runnable.execute();
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
private class MyTestRunner implements Runnable {
private final BlockJUnit4ClassRunner runner;
private final RunNotifier notifier;
private final FxApplicationTest fxApp;
public MyTestRunner(final BlockJUnit4ClassRunner runner, final RunNotifier notifier, final FxApplicationTest fxApp) {
this.runner = runner;
this.notifier = notifier;
this.fxApp = fxApp;
}
#Override
public void run() {
fxApp.startApp();
}
public void execute() throws InterruptedException {
fxApp.execute(runner, notifier);
}
}
}
Now, simply launch test using the runner :
import fr.samarie_projects.fx.utils.JUnitFxRunner;
#RunWith(JUnitFxRunner.class)
public class MainFxAppTest {
#org.junit.Test
public void testName() throws Exception {
MainFxApp fxApp = new MainFxApp();
fxApp.start(new Stage());
}
}
This unit test MainFxApp
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainFxApp extends Application {
#Override
public void start(final Stage stage) throws Exception {
StackPane root = new StackPane();
Scene scene = new Scene(root, 10, 10);
stage.setScene(scene);
}
public static void main(final String[] args) {
launch(args);
}
}
Sure, this code need to be reviewed. It is only to present the idea.
Well, considering that you might have your JavaFX app located at project-root/src/main/java/package/FXApp.java then you might have your tests located elsewhere like project-root/src/test/java/package/FXAppTest.java . This being the case, the FXAppTest class could call the FXApp class by initializing it using BeforeClass .
In theory you should be able to start your FX app with something like:
// imports located here that import junit 4.11+ packages (or TestNG)
public class FXAppTest {
#BeforeClass
public void initialize() {
FXApp fxa = new FXApp();
while ( fxa.isLoading() ) {
// do nothing
}
}
....
NOTE: Notice that FXAppTest does not extend Application here.
Now, if this doesn't clue you into the problem, you could enable JMX args on the JVM and then view the locked threads with JVisualVM.

NUnit Conditional Teardown?

Is there a way to do a conditional TearDown in NUnit?
I have a TestFixture which has a need to run cleanup code for just a few tests, and I don't really want to:
Run the TearDown method on every test
Create a private helper method and call it from the tests requiring cleanup if I can avoid it
There isn't unfortunately.
Can you not do the cleanup in the [TestFixtureTearDown] instead, so once all the tests have finished? I guess that depends on whether the cleanup has to be done before the next test runs.
Alternatively, put those tests that require a cleanup in another class/TextFixture together, away from the other tests. Then you can use a TearDown in there which doesn't need to be conditional.
Edit:
One thing I've just thought of, which could be done to achieve the aim though probably isn't actually worth it for this particular need, is that you can extend NUnit - create your own custom attributes which you could handle however you wanted. This is mentioned here. Like I say, I don't think really you should go down that route for this, but is useful to know none-the-less
You can have the main TearDown in a base class:
[TearDown]
public virtual void TearDown()
{
// Tear down things here
}
and then override it in the class where you have the tests that should not run the tear down code:
[TearDown]
public override void TearDown()
{
// By not calling base.TearDown() here you avoid tearing down
}
Extend all you classes with test from BaseTest
public class BaseTest
{
[SetUp]
public void BeforeTest()
{
GetService<NUnitHooksController>().ExecuteBeforeTestHooks(this);
}
[TearDown]
public void AfterTest()
{
GetService<NUnitHooksController>().ExecuteAfterTestHooks(this);
}
}
Use AfterTest and BeforeTest hooks. Works both with and without category.
public class ExampleTest : BaseTest
{
[Test, Category("asdasd")]
public void Test01()
{
...
}
[AfterTest("asdasd")]
public void ExampleHook()
{
...
}
}
public class NUnitHooksController
{
private readonly ILogger _log;
public NUnitHooksController(ILogger log)
{
_log = log;
}
public void ExecuteBeforeTestHooks(object testClass)
{
ExecuteHooks(testClass, typeof(BeforeTestAttribute));
}
public void ExecuteAfterTestHooks(object testClass)
{
ExecuteHooks(testClass, typeof(AfterTestAttribute));
}
private MethodInfo[] GetHookMethods(object currentTestClass, Type attributeType)
{
return currentTestClass
.GetType()
.GetMethods()
.Where(m => m.GetCustomAttributes(attributeType, false).Length > 0)
.ToArray();
}
private void ExecuteHooks(object testClass, Type requiredAttributeType)
{
var hooks = GetHookMethods(testClass, requiredAttributeType);
var testCategories = GetTestCategories();
foreach (var hook in hooks)
{
var allAttributes = hook.GetCustomAttributes(requiredAttributeType, true);
foreach (var attribute in allAttributes)
{
if (!attribute.GetType().IsEquivalentTo(requiredAttributeType))
{
continue;
}
var hookCategories = GetCategoriesFromAttribute(attribute);
// if we do not have specific category on hook
// or we have at least one same category on hook and test
if (!hookCategories.Any() || hookCategories.Intersect(testCategories).Any())
{
ExecuteHookMethod(testClass, hook);
}
}
}
}
private object[] GetTestCategories()
{
return TestContext.CurrentContext.Test.Properties["Category"].ToArray();
}
private void ExecuteHookMethod(object testClass, MethodInfo method)
{
var hookName = method.Name;
_log.Information($"Executing - '{hookName}' hook");
try
{
method.Invoke(testClass, Array.Empty<object>());
}
catch (Exception e)
{
_log.Error($"Executing of - '{hookName}' hook failed - {e}");
}
}
private string[] GetCategoriesFromAttribute(object attribute)
{
if (attribute is BeforeTestAttribute beforeTestAttribute)
{
return beforeTestAttribute.Categories;
}
if (attribute is AfterTestAttribute afterTestAttribute)
{
return afterTestAttribute.Categories;
}
throw new ArgumentException($"{attribute.GetType().FullName} - does not have categories");
}
}
I have solved this using the name of the test:
namespace TestProject
{
public class TestClass
{
// Test without TearDown
[Test]
public void Test1()
{
Assert.Pass("Test1 passed");
}
// Test with TearDown
[Test]
public void Test2()
{
Assert.Pass("Test2 passed");
}
[TearDown]
public void TearDown()
{
// Execute only after Test2
if (TestContext.CurrentContext.Test.Name.Equals(nameof(this.Test2)))
{
// Execute Test2 TearDown...
}
}
}
}
Or if you want to use the full name of Test2 (TestProject.TestClass.Test2) you can replace the line
if (TestContext.CurrentContext.Test.Name.Equals(nameof(this.Test2)))
by
if (TestContext.CurrentContext.Test.FullName.Equals(typeof(TestClass).FullName + "." nameof(this.Test2)))