I am trying to unit test the log statements generated in my code. I am using slfj, log4j and Mockito. I am using the similar code as below from the blog at
http://bloodredsun.com/2010/12/09/checking-logging-in-unit-tests/
When I run the test it throws exception saying that there are 0 invocations at line:
verify(mockAppender).doAppend(captorLoggingEvent.capture());
Error Message:
Wanted but not invoked: mockAppender.doAppend();
-> at testClass.testLogAdviceAfterReturning(DpsOpsLoggerTest2.java:94) Actually, there were zero interactions with this mock.
I see the logs printed on the console though. Request you to kindly help.
#RunWith(MockitoJUnitRunner.class)
public class ExampleThatLogsTest {
#Mock
private Appender mockAppender;
#Captor
private ArgumentCaptor captorLoggingEvent;
#Before
public void setup() {
LogManager.getRootLogger().addAppender(mockAppender);
}
#After
public void teardown() {
LogManager.getRootLogger().removeAppender(mockAppender);
}
#Test
public void shouldConcatAndLog() {
//given
ExampleThatLogs example = new ExampleThatLogs();
//when
String result = example.concat("foo", "bar");
//then
assertEquals("foobar", result);
verify(mockAppender).doAppend(captorLoggingEvent.capture());
LoggingEvent loggingEvent = captorLoggingEvent.getValue();
//Check log level
assertThat(loggingEvent.getLevel(), is(Level.INFO));
//Check the message being logged
assertThat(loggingEvent.getRenderedMessage(),
is("String a:foo, String b:bar"));
}
}
I tried to emulate your case ,At my end it is working fine
//Log Util
public class LogUtil{
final static Logger logger = Logger.getLogger(LogUtil.class);
public static Log`enter code here`ger getLogger()
{
return logger;
}
//class
public class RunMe {
public String runMe(String parameter) {
LogUtil.getLogger().info("This is info : " + parameter);
return "In runner " + parameter;
}
}
// Unit Test
#RunWith(MockitoJUnitRunner.class)
public class LoggerTest {
#Mock
private Appender mockAppender;
#Captor
private ArgumentCaptor captorLoggingEvent;
#Before
public void setup() {
LogUtil.getLogger().addAppender(mockAppender);
}
#Test
public void shouldConcatAndLog() {
RunMe runner=new RunMe();
String result=runner.runMe("XYZ");
assertEquals("In runner XYZ",result);
verify(mockAppender).doAppend((LoggingEvent) captorLoggingEvent.capture());
LoggingEvent logevent= (LoggingEvent) captorLoggingEvent.getValue();
assertThat(logevent.getLevel(), is(Level.INFO));
}
#After
public void tearDown() {
LogUtil.getLogger().removeAllAppenders();
}
}
I know this is a little bit outdated, but I was struggling with this too. I was logging statements at DEBUG level in the class under test. My configuration in logback.xml for the class under test was set to INFO. Changing my logging statement to INFO allowed the test to pass. In addition, I also read this Github post that is really concise and a clean implementation of testing log output. Hope others will find it useful.
Related
I am trying to test a method for the happy path and an Exception scenario.
My class looks like this
class MyClass
{
#Autowired
AnotherClass anotherClass;
public Object myMethod() throws MyException
{
try{
//DO SOME STUFF
anotherClass.anotherMethod();
}
catch(Exception e)
{
throw MyException(e);
}
}
}
I am testing the above myMethod like this.
#RunWith(MockitoJUnitRunner.class)
class MyClassTest
{
#Mock
AnotherClass anotherClass;
#InjectMocks
MyClass myClass;
#Test
public void myMethodTest()
{
when(anotherClass.anotherMethod()).thenReturn("Mocked data");
myClass.myMethod();
}
#Test(expected=MyException.class)
public void myMethodExpTest()
{
when(anotherClass.anotherMethod()).thenThrow(MyException.class);
myClass.myMethod();
}
}
When I checked the code coverage using Jacoco, it does not coverage the exception catch block. I tried debugging the test in my Eclipse IDE. I am getting the "Mocked Data" for the exception test method. It appears to be the mocking to that method is not getting reset for the second method.
Is there a way to flush the method mocking/stubbing from previous test methods?
First I would consider this a bug. But you can manually reset mocks
#Before
public void resetMock() {
Mockito.reset(anotherClass);
}
Im trying to make JUnit Test using PowerMock, but I have one problem. Here is my code:
public class MyGreeting extends MVCPortlet {
public static final String GREETING="greeting";
private static final String DEFAULT_GREETING="MY DEFAULT GREETING MESSAGE";
private static final Log _log = LogFactoryUtil.getLog(MyGreeting.class.getName());
#Override
public void render(RenderRequest req,RenderResponse res)
throws IOException, PortletException {
PortletPreferences prefs = req.getPreferences();
req.setAttribute(GREETING, prefs.getValue(GREETING, DEFAULT_GREETING));
super.render(req,res);
}
And I need to make JUnit test. I created another test package, new MyGreetingTest.java file, and come up to this code:
public class MyGreetingTest extends Mockito{
#BeforeClass
public static void setUpBeforeClass() throws Exception {
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
}
private MyGreeting portlet;
#Before
public void setUp() throws Exception {
portlet = new MyGreeting();
}
#After
public void tearDown() throws Exception {
}
#Mock
public RenderRequest request = mock(RenderRequest.class);
#Mock
PortletPreferences preferences = mock(PortletPreferences.class);
#Test
public final void renderTest() throws IOException, PortletException {
when(request.getPreferences()).thenReturn(preferences);
when(preferences.getValue(MyGreeting.GREETING, null)).thenReturn(value);
portlet.render(request, null);
String result = request.getAttribute(MyGreeting.GREETING).toString();
assertEquals(result, value);
}
But I have NullPointerException, because we can't apply getAttribute method to mock-request. Could you please tell me how to solve this problem? How can I test method with getAttribute method using Mockito?
I think you need to mock your method
Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00); // Mock implementation
when(stock.getValue()).thenCallRealMethod(); // Real implementation
I have a set of classes to work with REST methods in project. They look like this:
#Path("customer/")
#RequestScoped
public class CustomerCollectionResource {
#EJB
private AppManager manager; // working with DB
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response list(#QueryParam("email") String email) {
final List<Customer> entities = manager.listCustomers(email);
// adding customers to result
return Response.ok(result).build();
}
}
After that I've wrote test method:
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
#Test #GET #Path("projectName/customer") #Consumes(MediaType.APPLICATION_JSON)
public void test(ClientResponse<List<Customer>> response) throws Exception {
assertEquals(Status.OK.getStatusCode(), response.getStatus());
}
}
And I get NullPointerException when trying to run this test. It's because of empty response in test case. Why is this happens? DB is configured properly.
There are two modes an arquillian test can run: in-container and client mode. HTTP interfaces can be tested only in client mode (never tried the extensions, only used vanilla Arquillian for this).
By default the test methods executed in the context of the container, called by the arquillian test runner servlet.
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#EJB SomeBean bean; // EJBs can be injected, also CDI beans,
// PersistenceContext, etc
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
#Test
public void some_test() {
bean.checkSomething();
}
}
In client mode, the test methods are running outside of the container, so you don't have access to EJBs, EntityManager, etc injected into the test class, but you can inject an URL parameter for the test method.
#RunWith(Arquillian.class)
public class CustomerResourceTest {
// testable = false here means all the tests are running outside of the container
#Deployment(testable = false)
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
// baseURI is the applications baseURI.
#Test
public void create_account_validation_test (#ArquillianResource URL baseURI) {
}
You can use this URL parameter to build URLs to call your HTTP service using whatever method you have, like the new JAX-RS client API.
You can also mix the two modes:
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#EJB SomeBean bean;
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
}
#Test
#InSequence(0)
public void some_test() {
bean.checkSomething();
}
#Test
#RunAsClient // <-- this makes the test method run in client mode
#InSequence(1)
public void test_from_client_side() {
}
}
This is sometimes even necessary, because some extensions, like persistence cannot run in client mode.
I am using Fluent NHibernate and trying to do unit testing. Now I have a base test class which looks as follows:
[TestClass]
public abstract class BaseTest<TEntity> where TEntity : IBaseModel
{
private const string testDbFile = "test.db";
private static ISessionFactory sessionFactory;
protected static ISession session;
[TestMethod]
public void configureDB()
{
try
{
if (sessionFactory == null)
{
sessionFactory = Fluently.Configure()
.Database(SQLiteConfiguration.Standard
.UsingFile(testDbFile))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<AdminTest>())
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
}
}
private static void BuildSchema(Configuration config)
{
new SchemaUpdate(config).Execute(false, true);
}
[TestMethod]
public void sessionCreated()
{
session = sessionFactory.OpenSession();
}
[TestMethod]
public virtual void AddEntity_EntityWasAdded()
{
var entity = BuildEntity();
InsertEntity(entity);
session.Evict(entity);
var reloadedEntity = session.Get<TEntity>(entity.Id);
Assert.IsNotNull(reloadedEntity);
AssertAreEqual(entity, reloadedEntity);
AssertValidId(reloadedEntity);
}
There are also other methods which update and delete an entity. And I have AdminTest class which inherits BaseTest. In AdminTest I have following method:
[TestClass]
public class AdminTest : BaseTest<Admin>
{
[TestMethod]
public void SelectWorks()
{
IList<Admin> admins = session.QueryOver<Admin>().List();
Assert.AreNotEqual(0, admins.Count);
}
}
Here I always have exception, because session is null. Maybe I am wrong in the way of thinking how visual studio performs unit tests (I am newbie in it)?
Now I think like that, visual studio works in the following way
runs test-methods from BaseTest (there it configures database and creates session)
runs selectWorks method. Here I was thinking it should use session from BaseTest
Could you explain what is wrong in my way of thinking? And I want to be able to query from child classes, what is the right way of doing it?
Thanks, any help is appreciated, .
I would suggest using [TestInitialize] and [TestCleanup] in your abstract base class and doing something like the following:
[TestInitialize]
public void TestInitialize()
{
Console.Out.WriteLine("Get a ISession object");
}
[TestCleanup]
public void TestCleanup()
{
Console.Out.WriteLine("Dispose ISession");
}
Then in your child classes continue to do what you are doing:
[TestMethod]
public void DoDbWork()
{
Console.Out.WriteLine("Running a query via nhibernate");
}
You really just want to ensure you have a clean session for each test. The attributes for TestInitialize and TestCleanup will run before and after each unit test. Here is the documentation for those attributes.
To ensure your ISession is in the right state,follow something like this.
This is going to be an amateur level question. Is there a way to add start up code to a test project that uses MBUnit 3.4.0.0? I tried adding [TestFixture] and [FixtureSetUp] attributes to code that I wanted to run first, but unfortunately that didnt help.
The [FixtureSetUp] should be executed once before any test of the tests contained within the [TestFixture], but the two cannot be used interchangeably.
Here's a quick example. Admittedly the class doesn't have to be decorated with the [TestFixture] attribute, but it's good practice.
[TestFixture]
public class SimpelTest
{
private string value = "1";
[FixtureSetUp]
public void FixtureSetUp()
{
// Will run once before any test case is executed.
value = "2";
}
[SetUp]
public void SetUp()
{
// Will run before each test
}
[Test]
public void Test()
{
// Test code here
Assert.AreEqual("2", value);
}
[TearDown]
public void TearDown()
{
// Will run after the execution of each test
}
[FixtureTearDown]
public void FixtureTearDown()
{
// Will run once after every test has been executed
}
}