We recently moved from Play Framework 2.1 to 2.3 and some unit test stops working.
In this particular unit test, I'm using an object that extends Model from ebean. I make sure not to use any function from ebean (like find(), save() or update()).
Unfortunately, just by creating my object, I get an exception because it try to initiate the Model.Finder member, which I'm pretty sure it wasn't doing before the migration. How can I overcome this?
My setUp function that throw exception on the new call.
#Before
public void setUp() throws Exception {
SignageScheduleEntry allTheTimeSchedule = new SignageScheduleEntry();
}
My object itself, it fails on the new Model.Finder when debugging the unit test:
public static Model.Finder<Long,SignageScheduleEntry> find = new Model.Finder<>(Long.class, SignageScheduleEntry.class);
public SignageScheduleEntry() throws InvalidPeriodException {
....
}
In brief, I want to use my object without the ebean crap in my unit test like any object in any unit test. How can I achieve this?
Thanks!
As shown here:https://github.com/jamesward/play2torial/blob/master/JAVA.md#create-a-model
You will need to create a "fakeApplication" like so:
import org.junit.Test;
import static play.test.Helpers.fakeApplication;
import static play.test.Helpers.running;
import static org.fest.assertions.Assertions.assertThat;
import models.Task;
public class TaskTest {
#Test
public void create() {
running(fakeApplication(), new Runnable() {
public void run() {
Task task = new Task();
task.contents = "Write a test";
task.save();
assertThat(task.id).isNotNull();
}
});
}
}
If that doesn't work, or if that's not what you're looking for, another approach is more complex and convoluted from the Play Java docs:
https://www.playframework.com/documentation/2.3.x/JavaTest#Unit-testing-models
You basically have to create a wrapper for the Model, and mock out the wrapper in the unit tests.
Related
We use testng as out testing framework. We also use Lombok #Log4j2 to instantiate our log objects. I need to test some code that it logs certain messages under certain conditions.
I have seen examples using junit and Mockito. But I cannot find how to do it in testng. Switching to junit is not an option.
Edit
I have implemented a class (CaptureLogger) which extends AbstractLogger
import org.apache.logging.log4j.spi.AbstractLogger;
public class CaptureLogger extends AbstractLogger {
...
}
I am unable to to hook it up to the logger for the class under test.
CaptureLogger customLogger = (CaptureLogger) LogManager.getLogger(MyClassUnderTest.class);
generates an error message:
java.lang.ClassCastException: org.apache.logging.log4j.core.Logger cannot be cast to CaptureLogger
I have found out that LogManager.getLogger returns the Logger interface, not the Logger object (which implements the Logger interface).
How can I create an instance of my CaptureLogger?
You can define your own appender like this:
package com.xyz;
import static java.util.Collections.synchronizedList;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
#Plugin(name = "LogsToListAppender", category = "Core", elementType = Appender.ELEMENT_TYPE)
public class LogsToListAppender extends AbstractAppender {
private static final List<LogEvent> events = synchronizedList(new ArrayList<>());
protected LogsToListAppender(String name, Filter filter) {
super(name, filter, null);
}
#PluginFactory
public static LogsToListAppender createAppender(#PluginAttribute("name") String name,
#PluginElement("Filter") Filter filter) {
return new LogsToListAppender(name, filter);
}
#Override
public void append(LogEvent event) {
events.add(event);
}
public static List<LogEvent> getEvents() {
return events;
}
}
Then create a file called log4j2-logstolist.xml in the root of the classpath where the appender will be referenced:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="com.xyz" >
<Appenders>
<LogsToListAppender name="LogsToListAppender" />
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="LogsToListAppender" />
</Root>
</Loggers>
</Configuration>
You should take special care (to update it properly) of the attribute packages="com.xyz" (the package of your appender) or it won't be available. For more information check https://www.baeldung.com/log4j2-custom-appender
And finally create TestNG test:
package com.xyz;
import static org.testng.Assert.assertTrue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.config.Configurator;
import org.testng.annotations.Test;
#Test
public class LogsTest {
static {
Configurator.initialize(null, "classpath:log4j2-logstolist.xml");
}
#Test
public void testLogs() {
// call your code that produces log, e.g.
LogManager.getLogger(LogsTest.class).trace("Hello");
assertTrue(LogsToListAppender.getEvents().size() > 0);
}
}
As you can see we are forcing Log4j2 to use the custom configuration with Configurator.initialize(null, "classpath:log4j2-logstolist.xml"); when the class is initialized (static{} block).
Keep in mind that it will be useful for you to check logger name as well, e.g. LogsToListAppender.getEvents().stream().filter(a -> CLASS_THAT_PRODUCES_LOG.class.getName().equals(a.getLoggerName())).collect(toList());
you can access the actual message using LogEvent::getMessage() method
As Long as you're using Lombok for logger generation you can't do much at the level of the source code itself with the given tools. For example, if you place #Log4j2 annotation, it generates:
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
The compiled code already comes with this line.
You can try to mock LogManager.getLogger method with PowerMockito but I don't really like this kind of tools. Stating this though since it can be a viable direction.
There are couple of ways to work with the framework itself.
One way (and I'm not familiar with Log4j2 specifically but it should offer this capability - I did something similar with Log4j 1.x many years ago) is to provide your own implementation of logger and associate it with the logger factory at the level of Log4j2 configurations.
Now if you do this, then the code generated by lombok will return your instance of logger that can memorize the messages that were logged at different levels (it's the custom logic you'll have to implement at the level of Logger).
Then the logger will have a method public List<String> getResults() and you'll call the following code during the verification phase:
public void test() {
UnderTest objectUnderTest = ...
//test test test
// verification
MyCustomLogger logger = (MyCutomLogger)LogManager.getLogger(UnderTest.class);
List<String> results = logger.getResults();
assertThat(results, contains("My Log Message with Params I expect or whatever");
}
Another somewhat similar way I can think of is to create a custom appender that will memorize all the messages that were sent during the test. Then you could (declaratively or programmatically bind that appender to the Logger obtained by the LogFactory.getLogger for the class under test (or also for other classes depending on your actual needs).
Then let the test work and when it comes to verification - get the reference to the appender from the log4j2 system and ask for results with some public List<String> getResults() method what must exist on the appender in addition to the methods that it must implement in order to obey the Appender contract.
So the test could look something like this:
public void test () {
MyTestAppender app = createMemorizingAppender();
associateAppenderWithLoggerUnderTest(app, UnderTest.class);
UnderTest underTest = ...
// do your tests that involve logging operations
// now the verification phase:
List<String> results = app.getResults();
assertThat(results, contains("My Log Message with Params I expect or whatever");
}
I am using Rhino.Mocks and Structure map to help unit test my code. I have several tests that pass when they are ran by themselves, but when ran as a group fail to pass. The setup code for these unit tests is:
[TestInitialize()]
public void Setup()
{
ObjectFactory.Initialize(x =>
{
x.For(IManager)().Use(Handler)();
});
}
In my tests, I stub out this interface and call the method.
[TestMethod]
public void AreMultiple_Test()
{
var mackIManager = MockRepository.GenerateMock<IManager>();
mackIManager.Stub(u => u.GetTwoUserName(Arg<int>.Is.Anything)).Return(null);
ObjectFactory.Inject(typeof(IManager), mackIManager);
StepAdditionalActionBase actionBase = new StepAdditionalActionBase();
bool areMultiple = actionBase.AreMultiple(new WorkOrder { Id = "123" });
Assert.IsFalse(areMultiple);
}
Test Method 2
[TestMethod]
public void AreMultiple_Test()
{
var mackIManager = MockRepository.GenerateMock<IManager>();
mackIManager.Stub(u => u.GetTwoUserName(Arg<int>.Is.Anything)).Return("123");
ObjectFactory.Inject(typeof(IManager), mackIManager);
StepAdditionalActionBase actionBase = new StepAdditionalActionBase();
bool areMultiple = actionBase.AreMultiple(new WorkOrder { Id = "123" });
Assert.IsTrue(areMultiple);
}
This is unit testing the following code.
public bool AreMultiple(WorkOrder workOrder)
{
string secondUser = _handler.GetTwoUserName(_workflowManager.GetNumberForProject(workOrder.Id));
if (String.IsNullOrEmpty(secondUser ))
{
return false;
}
return true;
}
When I run them by themselves, they work fine. When I run them together, the first passes and the second fails. When I debug the second one, I find that that the return value in the Stubbed method is still coming back as null. How do I get this to use the new Stubbed method.
UPDATE.
I am using StructureMap as my container. From what I have been able to find, the following code is what is used to dispose of the container I got it from this link. When I added this, the test still fail when ran together, but pass when ran individually.
[TestCleanup()]
public void TestCLeanup()
{
ObjectFactory.Container.Dispose();
}
The tests work one by one but fails if run all together. The problem should be in the common part which is being shared across the tests making them dependent from each other. In this particular case that is static ObjectFactory which is nothing else but a Service Locator (anti-pattern).
In the tests, you mock the IManager interface and register it in the ObjectFactory:
ObjectFactory.Inject(typeof(IManager), mackIManager);
Then the SUT uses the ObjectFactory service locator to resolve and use the mocked interface (_handler field):
string secondUser = _handler.GetTwoUserName(...)
I suspect the first test registers the _handler and never clean it up properly, so that the same instance appears in the second test. You should reset the ObjectFactory between tests following the Register Resolve Release pattern.
Another (preferable) option is to refactor your SUT to receive the IManager handler dependency explicitly via constructor. That would simplify both SUT and tests moving the ObjectFactory configuration to the Composition Root.
I'm trying to run this unit test, I'm currently using Xtend over Java in order to read the code easily.
The test consist on an admin who must verify a user in order to add it or not to the current repository. I want to make that admin a mock object in order to verify if the user has send correctly the method "generateProfile", which do the following
class User{
#Accessors
repositoryAdministrator admin
def generateProfile{
admin.add(this)
}
the method add is the following:
class repositoryAdministrator{
#Accessors List<User> objects
#Accessors List<User> usersToValidate
def add(User user){
usersToValidate.add(user)
}
This is the test i want to run using the lib Mockito
#RunWith(MockitoJUnitRunner)
class MockitoTests{
val lala = new User()
#Mock
repositoryAdministrator fakeAdmin
#Before
def void init(){
MockitoAnnotations.initMocks(this)
}
#Test
def validationTest(){
lala.admin = fakeAdmin
lala.generateProfile
Mockito.verify(fakeAdmin).add(lala)
}
}
I have imported correctly the libraries, I'm working on an Eclipse IDE, and when i run the test I keep on getting initializationError.
How do I properly initialize a mock object using Mockito? Sorry for my English
I've already found the problem, test using Xtend are not necessary to define the return type... Until you implement Mockito dependencies on a Maven proyect. There was a problem in the add method of the admin, it return a bool variable and it should return void, the way to fix it was:
#RunWith(MockitoJUnitRunner)
class MockitoTests{
val lala = new User()
#Mock
repositoryAdministrator fakeAdmin
#Before
def void init(){
MockitoAnnotations.initMocks(this)
}
#Test
def void validationTest(){
lala.admin = fakeAdmin
lala.generateProfile
Mockito.verify(fakeAdmin).add(lala)
}
}
I only define the return type in the test, which should be in this case void
When running unit tests, I'd like to fail any tests during which ERROR level message is logged. What would be the easiest way to achieve this using SLF4J/Logback? I'd like to avoid writing my own ILoggerFactory implementation.
I tried writing a custom Appender, but I cannot propagate exceptions through the code that's calling the Appender, all exceptions from Appender get caught there.
The key is to write a custom appender. You don't say which unit testing framework you use, but for JUnit I needed to do something similar (it was a little more complex than just all errors, but basically the same concept), and created a JUnit #Rule that added my appender, and the appender fails the test as needed.
I place my code for this answer in the public domain:
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import org.junit.rules.ExternalResource;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.fail;
/**
* A JUnit {#link org.junit.Rule} which attaches itself to Logback, and fails the test if an error is logged.
* Designed for use in some tests, as if the system would log an error, that indicates that something
* went wrong, even though the error was correctly caught and logged.
*/
public class FailOnErrorLogged extends ExternalResource {
private FailOnErrorAppender appender;
#Override
protected void before() throws Throwable {
super.before();
final LoggerContext loggerContext = (LoggerContext)(LoggerFactory.getILoggerFactory());
final Logger rootLogger = (Logger)(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME));
appender = new FailOnErrorAppender();
appender.setContext(loggerContext);
appender.start();
rootLogger.addAppender(appender);
}
#Override
protected void after() {
appender.stop();
final Logger rootLogger = (Logger)(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME));
rootLogger.detachAppender(appender);
super.after();
}
private static class FailOnErrorAppender extends AppenderBase<ILoggingEvent> {
#Override
protected void append(final ILoggingEvent eventObject) {
if (eventObject.getLevel().isGreaterOrEqual(Level.ERROR)) {
fail("Error logged: " + eventObject.getFormattedMessage());
}
}
}
}
An example of usage:
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExampleTest {
private static final Logger log = LoggerFactory.getLogger(ExampleTest.class);
#Rule
public FailOnErrorLogged failOnErrorLogged = new FailOnErrorLogged();
#Test
public void testError() {
log.error("Test Error");
}
#Test
public void testInfo() {
log.info("Test Info");
}
}
The testError method fails and the testInfo method passes. It works the same if the test calls the real class-under-test that logs an error as well.
Logging frameworks are generally designed not to throw any exceptions to the user. Another option (in addition to Raedwald's answer) would be to create a custom appender that sets a static boolean flag to true when an ERROR message is logged, reset this flag in a setup method and check it in a teardown method (or create a JUnit rule to reset/check the flag).
So, you want to fail your test case if any error reporting message of the logger is called.
Use dependency injection to associate the code to be tested with the logger it should use.
Implement a test double that implements the SLF4J logger interface, and which does nothing for most methods, but throws an AssertionError for the error logging methods.
In the set-up part of the test case, inject the test double.
I am trying to get a custom JSON renderer for exceptions working in my REST api.
I was able to get a custom marshaller working that did most of what I needed, but I would like to have control over the context that I don't have access to in the marshaller. The grails documentation shows how to write a custom renderer, and I have one that I think should work, but I can't use it during unit testing my REST controller.
Grails docs: http://grails.org/doc/2.3.4/guide/webServices.html#customRenderers
Does anyone know how I would initialize this renderer to be used in my controller actions during unit testing?
The above documentation only says how to set it up in the resources.groovy file.
When I was using the marshaller, I was able to do:
def setup(){
//Set up the custom JSON marshallers
JSON.registerObjectMarshaller(new CusomMarshaller(), 1)
}
But I don't see an equivalent method for Renderers. Can anyone point me in the right direction?
Further details:
Here is my renderer:
class JSONExceptionRenderer extends AbstractRenderer<Exception>{
JSONExceptionRenderer(){
super(Exception, [MimeType.JSON, MimeType.HAL_JSON, MimeType.TEXT_JSON] as MimeType[])
}
#Override
void render(Exception object, RenderContext context) {
log.warn("RENDERING")
Exception exception = (Exception) object
//Default to internal error
Integer code = 500
//If it is a defined exception with a more appropriate error code, then set it
if(exception instanceof RestException){
code = (Integer) ((RestException) exception).getCode()
}else if(exception instanceof MissingResourceException){
code = 404
}
context.status = HttpStatus.valueOf(code)
//Write the JSON
Writer writer = context.getWriter()
Map content = ["code":code, "status":"error", "message":exception.message]
JsonBuilder builder = new JsonBuilder(content)
builder.writeTo(writer)
}
}
And this is the way I am trying to get it to work:
try{
log.info "Throwing exception"
throw new NullPointerException("Test Exception")
}catch(Exception ex){
render ex as JSON
}
Thanks!
If you are using spock, you can inject the bean directly in Specification.
#TestFor(MyController)
class MyControllerSpec extends spock.lang.Specification {
def myCustomRenderer //bean name used in resources.groovy
//continue with tests
}
If you are using junit tests, then you can use defineBeans as:
#TestFor(MyController)
class MyControllerTests {
void setup() {
defineBeans {
myCustomRenderer(com.example.MyCustomRenderer)
}
}
//continue with tests
}
You can refer this answer as well for use of defineBeans.
I believe this is what you just need to do to test the behavior of the renderer.
After much digging around in the source. I thought I would post this here for others.
The reason my custom renderer didn't work was you have to use the "respond" method on the controller:
respond object
That will check the class ControllersRestApi with a very large respond method to find your renderer in the rendererRegistry and use it. This is different than the object marshallers which use the render as notation.
In addition you need to also flush the writer, which wasn't in the orgininal documentaiton:
builder.writeTo(writer)
writer.flush()