How can I test RESTful methods with Arquillian? - unit-testing

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.

Related

Unable to unit test a spring service calling mocked custom repository

I defined a custom repository Interface which get stream of entities through Query.getResultStream
public interface MyRepository<T> {
Stream<T> findByCriteria(...);
}
public class MyRepositoryImpl<T> implements MyRepository<T> {
#Autowired SessionFactory sessionFactory;
public Stream<T> findByCriteria(...) {
...
}
}
and my Repository & Service
#Repository
public interface EntityRepository extends MyRepository<Entity> {
...
}
#Service
#Transactional(readOnly = true)
public class EntityService {
#Autowired EntityRepository entityRepository;
public Stream<Entity> getEntitiesByCriteria(String criteria) {
...
return entityRepository.findByCriteria(...);
}
}
Problem is my Service Unit Test does not see the repository implementation, and always return null without going inside findByCriteria implementation.
ExtendWith(MockitoExtension.class)
class EntityServiceTest {
#InjectMocks EntityService service;
#Mock EntityRepository repository;
#Test
void test() {
...
when(repository.findByCriteria(...))
.thenReturn(...);
service.getEntitiesByCriteria(...); //This does not see the implementation of findByCriteria in MyRepositoryImpl
]
}
I tried many annotations like #RepositoryDefinition in my interface or #EnableJpaRepositories in my test class but nothing seems to work

Mockito: verify the captured object's method is called

I am using Mockito to write a simple unit test. I have a smiple abstract class which implements Runnable:
public abstract class MyRunnable implements Runnable {
#Override
public void run() {
doTask();
}
public abstract void doTask();
}
Then, a function under test uses MyRunnable:
public class MyService {
public void something() {
executor.execute(new MyRunnable() {
#Override
doTask() {
…
}
});
}
}
My test case, I want to test doTask() has run :
#Test
public void testSomething() {
…
ArgumentCaptor<MyRunnable> myCaptor = ArgumentCaptor.forClass(MyRunnable.class);
verify(mockMyService).something(myCaptor.capture());
// get what has been captured
MyRunnable myRunnable = myCaptor.getValue();
//verify doTask() has run , but got ERROR.
verify(myRunnable).doTask();
}
My test case throw the following error:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type and is not a mock!
The error complains that verify() only accept mocked object. Then, how can I verify/test that the captured MyRunnable object has run doTask() with Mockito?
If you have control over your codebase, you can make your code testable with Mockito by moving any code that uses the new keyword into a separate Factory class like so...
public class MyService {
private MyRunnableFactory = factory;
public MyService(MyRunnableFactory factory) {
this.factory = factory;
}
public void something() {
executor.execute(factory.createInstance());
}
}
Then your test can simply inject a Mock of the factory which you can verify its behaviour/interactions
#Mock MyRunnableFactory factory;
#Mock MyRunnable myRunnable;
#Test
public void testSomething() {
when(factory.createInstance()).thenReturn(myRunnable);
// method under test
MyService service = new MyService();
service.something();
verify(myRunnable).doTask();
}
I use a rule of thumb that classes that creates objects, shouldn't have any business logic, so you don't have these testing headaches. This is essentially the Single Responsibilty Principal
You can't do this with Mockito because MyRunnable is created by the code under test. But you may have a look at PowerMock because it allows you to mock the constructor: https://github.com/jayway/powermock/wiki/MockConstructor

Mockito Mock log4j appender is not invoked while running unit test

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.

How to mock HttpSession in JSF

i have a service method that get session attribute and i want to make unit test for this service method and i was wondering how to mock the HttpSession in jsf.
1- use the FacesContextMocker class:
public abstract class FacesContextMocker extends FacesContext {
private FacesContextMocker() {}
private static final Release RELEASE = new Release();
private static class Release implements Answer<Void> {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
setCurrentInstance(null);
return null;
}
}
public static FacesContext mockFacesContext() {
FacesContext context = Mockito.mock(FacesContext.class);
setCurrentInstance(context);
Mockito.doAnswer(RELEASE).when(context).release();
return context;
}
}
2- in the test class #Before method do the following:
FacesContextMocker.mockFacesContext();
ExternalContext externalContext = Mockito.mock(ExternalContext.class);
Mockito.when(FacesContext.getCurrentInstance().getExternalContext())
.thenReturn(externalContext);
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Mockito.when(
FacesContext.getCurrentInstance().getExternalContext()
.getRequest()).thenReturn(request);
HttpSession httpSession = Mockito.mock(HttpSession.class);
Mockito.when(GeneralUtils.getHttpSession()).thenReturn(httpSession);
3- the getHttpSession method is as follows:
public static HttpSession getHttpSession() {
return ((HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest()).getSession();
}
4- in the test method do the following:
Mockito.when(
GeneralUtils.getHttpSession().getAttribute(
"userID")).thenReturn("1");
5- this is assuming that in your service method that you are making the unit test for you have code like:
String currentUserID = (String) GeneralUtils.getHttpSession()
.getAttribute(userID);

Nhibernate unit testing. Child class cannot use Base class property

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.