Mocking dependencies inside of an AOP object using Testbox and AOP/1 - unit-testing

I am curious if there is an easier way to mock the dependencies inside a component that uses AOP.
For example I have a component that uses CRUD methods to persist changes to the database. For audit logging I figured I could use AOP so I didn't have to put my logging calls inside of the methods. The issue that I am running into is during unit testing when I want to mock the database and session storage used inside the object that provides the AOP. The only way I have been able to figure out how to fake the database and session is to create a new mock component file that extends the original and then overrides the init method. Using this method is not very flexible as I have to create several extra files for a simple unit test. Below is some of the test code:
This is the bean that gets created with the di/1 bean factory:
//customerBean.cfc
component accessors="true" extends="models.abstracts.AbstractModel" displayname="Customer" {
property name="ID" type="numeric" default="0";
property name="Name" type="string" length="100" default="<Unknown>" logEvents="update";
property name="Type" type="string" default="Homeowner" logEvents="update";
property name="Status" type="string" default="Active" logEvents="update";
public any function init(customerDAO) {
variables.DAO = arguments.customerDAO;
}
}
Here is the component that the customerBean extends:
//abstractModel.cfc
component accessors="true" {
public any function doCreate(required struct data) {
setID(save());
return getID();
}
}
This is the AOP component that has two dependencies that need to be mocked:
//customerLogger.cfc
component accessors="true" {
property name="tableToLogTo" default="CustomerLogs" setter="false";
public any function init(LoggerServiceDAO, scopeStorage) {
variables.loggerServiceDAO = arguments.loggerServiceDAO;
variables.scopeStorage = arguments.scopeStorage;
}
public any function after(targetBean, methodName, args, result) {
variables.loggerServiceDAO.insertLog(method=arguments.methodName, user=variables.scopeStorage.get('session.user.id'));
}
}
Here is the code I use to get the CustomerBean:
bf = new framework.aop(
folders="/models,/system,/tests/Mocks", config={transients=["entity", "process", "transients", "report", "forms"],transientPattern="Bean$"}
);
bf.intercept('CustomerBean', 'CustomerLoggerMock', 'doCreate');
customerBean = bf.getBean('CustomerBean', {customerDAO: customerDAOMock});
Ideally what I would like to do is use Testbox to mock the two objects and use the nice built in verification methods. Is this possible or am I stuck creating all of these mock files?

Related

Dependency Variable Doesnt Exist

Newbie in coldbox so please have patience with me.
I am trying to implement TDD on my coldbox application.
Under my service model I inject this dependency.
property name="wirebox" inject="wirebox"
property name="populator" inject="wirebox:populator";
On my service model I have this method. GetallUsers()
User function new(){
return wirebox.getInstance("User");
}
function getAllUsers(){
var users= queryExecute(
"SELECT * FROM USERS",
{},
{returnType="array"}
).map(function(user){
return populator.populateFromStruct(new(),user);
});
return users;
}
And on my UserServiceTest I have this code:
component extends="coldbox.system.testing.BaseModelTest" model="models.UserService"{
/*********************************** LIFE CYCLE Methods ***********************************/
function beforeAll(){
super.beforeAll();
// setup the model
super.setup();
// init the model object
model.init();
}
function afterAll(){
super.afterAll();
}
/*********************************** BDD SUITES ***********************************/
function run(){
describe( "Users Suite", function(){
it( "can get list of users", function(){
var stubPopulator = stub().$( 'populateFromStruct', {} );
model.$property( 'populator', 'variables', stubPopulator );
var users= model.getAll();
expect( event.getPrivateValue( "users") ).toBeStruct();
});
});
}
But I got this error saying **variable [POPULATOR] doesn't exist**.
Hoping someone can help me.
You didn't show the full test bundle, but based on the name it would appear it is a unit test (or a ColdBox model test, which is a type of unit test). Unit tests do not spin up the ColdBox framework by default and do not process injections for the CFCs under test. They are created "naked" and it's up to you to provide mocks for an dependencies that CFC has.
So in this case, you'd need to provide a mock populator to your model to be used for the test. So something like this:
var stubPopulator = createStub().$( 'populateFromStruct', {} )
model.$property( 'populator', 'variables', stubPopulator )
var users= model.getAll();
My stubed populator just returns an empty struct. It's also worth noting I don't think your queryMap() is returning a struct like you think it is so you may need to confirm the functionality of that method.
Alternatively, you could switch to more of an integration test where you set this.loadColdBox to true in your test CFC's pseduo-constructor and then use getInstance( 'UserService' ) to get a fully built instance of your UserService which would have the populator injected into it. Exactly how this would look like depends on several things you haven't shared such as your test harness setup, and your test bundle CFC's base class.

Mocking a REST Datasource in a Model TestCase for CakePHP

I am using the CakePHP-ReST-DataSource-Plugin Datasource for hitting a RESTful service in my model. This implies that the models will not have a database connection.
I have successfully accessed the services and would now like to write unit tests for the models. This is proving to be a daunting task since I cannot succeed to mock the datasource so that I do not hit the actual remote Service but rather return expected results for the tests.
<?php
App::uses('KnowledgePoint', 'Model');
class KnowledgePointTest extends CakeTestCase{
public $fixtures = array('app.knowledgepoint');
public $useDbConfig = 'RestTest';
private $KnowledgePoint;
public function setUp() {
parent::setUp();
$this->KnowledgePoint = ClassRegistry::init('KnowledgePoint');
/**
* This is the confusing part. How would I mock the datasource
so that I can mock the request method which returns the data
from the api?
*/
$this->KnowledgePoint->DataSource = $this->getMockForModel(
'RestSource',array('request'));
}
public function tearDown() {
parent::tearDown();
}
}
I would like to be able to mock the datasource and stub the request method to return data that would normally be returned from the remote service.
Kind regards,
Roland
Mocking the model and its getDataSource() method so that it returns your mocked datasource should theoretically work. Here's an example
App::uses('RestSource', 'Rest.Model/Datasource');
$DataSource = $this->getMock('RestSource', array('request'), array(array()));
$DataSource
->expects($this->any())
->method('request')
->will($this->returnValue('some custom return value'));
$Model = $this->getMockForModel('KnowledgePoint', array('getDataSource'));
$Model
->expects($this->any())
->method('getDataSource')
->will($this->returnValue($DataSource));
$Model->save(/* ... */);
In case you are wondering about the array(array()) for the datasource mock, this is required as the RestSource constructor doesn't supply a default value for the first argument (unlike the parent constructor).

Grails Unit Test Service MissingProperty 'log'

I want to run a unit test for a service. The method I want to test includes a some log.debug() statements. While the log property is injected at runtime, it does not seem to be injected in tests, so it throws groovy.lang.MissingPropertyException: No such property: log for class:
This is my unit test class:
#TestFor(ServiceUnderTest)
#Mock([ServiceUnderTest])
class ServiceUnderTestTests {
def test() {
def mock = [ mockedProp: [...] ] as ServiceUnderTest
def info = mock.doOperation()
assert ....
}
}
I've also tried adding MockUtils.mockLogging(ServiceUnderTest) but with no success.
How can I get the log property properly injected in my service class while in unit tests?
You do not have to have the test class annotated with #Mock([ServiceUnderTest]). #TestFor(ServiceUnderTest) detects its a service class and does all the mocking automatically. It also adds a service property to the test class that can be accessed in all the test methods and mocks the log property accordingly.
I think the problem why neither mocking nor explicit log mocking with MockUtils.mockLogging(ServiceUnderTest) does work in your case is the as coercion you are using in your test method code:
def mock = [ mockedProp: [...] ] as ServiceUnderTest
Groovy internally uses java.lang.reflect.Proxy to create a proxy descendant class from ServiceUnderTest. The proxy class does not see changes done to the ServiceUnderTest meta class like the added log property.
I would solve this issue by using a per-object meta class. You can mock the property getter (or setter) by altering the metaClass of the service object. Be aware that meta-class changes are rolled back by Grails in-between execution of test methods:
service.metaClass.mockedProp = {-> ... }

Unittesting and mocking robotlegs service calls using Oil extension

I have an ExampleModel that calls to an ExampleService that retrieves data from our backend. I can't figure out how to write unit tests for my application; which is structured as shown below:
ExampleService
public function retrieveMyToDoList(parameters):Promise
{
var promise:Promise = performRequest({request: "call to backend", parameters: values, session_id: clientModel.sessionID});
promise.addResultProcessor(parseRetrieveToDoListResult);
return promise;
}
protected function parseRetrieveToDoListResult(data:Object, callback:Function):void
{
does some JSON parsing into an object
callback(null, object containing my retrieved data)
}
ExampleModel
public function getMyToDoList():Promise
{
var promise:Promise = exampleService.retrieveToDoList(parameters);
promise.addResultHandler(onGetToDoListResult);
promise.addErrorHandler(onGetToDoListError);
return promise;
}
private function onGetHeadrsByUserResult(promise:Promise):void
{
// where this event will be listened to by mediators etc
dispatchEvent(new ResponseEvent(GOOD_RESULT));
}
private function onGetHeadrsByUserError(promise:Promise):void
{
dispatchEvent(new ResponseEvent(BAD_RESULT));
}
I'm trying to use asmock to mock my Service so that I can test my Model and how it handles the various results in the resulting Object but how do I mock the callback? I saw examples where the return values were mocked but in my case I'm using the Promise and callback and I'm not too sure how to go ahead.
If someone could please advise.
Thanks!
You can let the mock service return a real promise and call the handleResult method of the promise directly.
FYI: it's not a good idea to have a direct dependency from the model to the service. You should let the service manipulate the model, or pass the results from the service to a command which will manipulate the model. Models should never depend on anything else than helper classes.

How to test Hibernate criteria queries without using any database?

I'm developing a Java application with lots of complex Hibernate criteria queries. I would like to test these criteria to make sure they are selecting the right, and only the right, objects. One approach to this, of course, is to set up an in-memory database (e.g. HSQL) and, in each test, make a round trip to that database using the criteria and then assert that the query results match my expectations.
But I'm looking for a simpler solution, since Hibernate criteria are just a special kind of logical predicates about Java objects. Thus they could, in theory, be tested without accessing any database at all. For example, assuming that there is a entity called Cat:
class Cat {
Cat(String name, Integer age){
this.name = name;
this.age = age;
}
...
}
I would like to do something like this, to create criteria queries:
InMemoryCriteria criteria = InMemoryCriteria.forClass(Cat.class)
.add(Restrictions.like("name", "Fritz%"))
.add(Restrictions.or(
Restrictions.eq("age", new Integer(0)),
Restrictions.isNull("age")))
assertTrue(criteria.apply(new Cat("Foo", 0)))
assertTrue(criteria.apply(new Cat("Fritz Lang", 12)))
assertFalse(criteria.apply(new Cat("Foo", 12)))
The criteria could be used in production code like this:
criteria.getExecutableCriteria(session); //similar to DetachedCriteria
Is there any Java library that makes this kind of test possible?
You could use a mocking framework like Mockito to mock all relevant Hibernate classes and define expected behavior of these mocks.
Sounds like a lot of code, but since the Hibernate Criteria API is a fluent interface, all methods of Criteria return a new instance Criteria. So defining the mock behavior which is common to all tests is simple.
Here is an example using Mockito
#Mock
private SessionFactory sessionFactory;
#Mock
Session session;
#Mock
Criteria criteria;
CatDao serviceUnderTest;
#Before
public void before()
{
reset(sessionFactory, session, criteria);
when(sessionFactory.getCurrentSession()).thenReturn(session);
when(session.createCriteria(Cat.class)).thenReturn(criteria);
when(criteria.setFetchMode(anyString(), (FetchMode) anyObject())).thenReturn(criteria);
when(criteria.setFirstResult(anyInt())).thenReturn(criteria);
when(criteria.setMaxResults(anyInt())).thenReturn(criteria);
when(criteria.createAlias(anyString(), anyString())).thenReturn(criteria);
when(criteria.add((Criterion) anyObject())).thenReturn(criteria);
serviceUnderTest = new CatDao(sessionFactory);
}
All methods of the Criteria mock return the mock again.
In a concrete test you would then use a ArgumentCaptor and verify statements to investigate what happened to the mocked Criteria.
#Test
public void testGetCatByName()
{
ArgumentCaptor<Criterion> captor = ArgumentCaptor.forClass(Criterion.class);
serviceUnderTest.getCatByName("Tom");
// ensure a call to criteria.add and record the argument the method call had
verify(criteria).add(captor.capture());
Criterion criterion = captor.getValue();
Criterion expectation = Restrictions.eq("name", "Tom");
// toString() because two instances seem never two be equal
assertEquals(expectation.toString(), criterion.toString());
}
The problem I see with this kind of unitests is that they impose a lot of expectations about the class under test. If you think of serviceUnderTest
as a blackbox, you can't know how it retrieves the cat object by name. It could also use a LIKE criterion or even 'IN' instead of =, further it could use the
Example criterion. Or it could execute a native SQL query.
I think, you must do an integration test here with H2 or other in-memory database. As you said, if you only use mocks, you can see how object interacts with each other, but you never know what result list you get.
I am on the same page, not with Restriction or so, but with JPA 2.0 CriteriaQuery and CriteriaBuilder. I build complex predicates in my persistence layer, and at last, I find it becomes inevitable to test with data in db, as no one knows what would be the final query in SQL. And I decide that in this part of the system, an integration is needed, so I went for it.
At last it is not very hard to build such a test. You need H2 dependency, a persistence.xml like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- For H2 database integration tests. -->
<!-- For each int test, define unique name PU in this file and include SQL files in different paths. -->
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="test-item-history-service-bean" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider> <!-- mind here: must be this! cannot be JPA provider! -->
<class>com.data.company.Company</class>
<class>com.data.company.ItemHistory</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=Oracle;INIT=RUNSCRIPT FROM 'src/test/resources/db/item-history/create.sql'\;RUNSCRIPT FROM 'src/test/resources/db/item-history/populate.sql'"/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/> <!-- mind here! Can only be "update"! "create-drop" will prevent data insertion! -->
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.default_schema" value="main"/>
</properties>
</persistence-unit>
</persistence>
(Mind very carefully the comment in the XML above, it took me a week to finally solve them)
Note about the provider: see here: How to configure JPA for testing in Maven
And in the two sql files, you CREATE TABLE ... and INSERT INTO .... Insert whatever you like, as the data is part of the test.
And, a test like this:
/**
* Integration tests with in-memory H2 DB. Created because:
* - In-memory DB are relatively cheap to create and destroy, so these tests are quick
* - When using {#link javax.persistence.criteria.CriteriaQuery}, we inevitably introduce complex perdicates'
* construction into persistence layer, which is a drawback of it, but we cannot trade it with repetitive queries
* per id, which is a performance issue, so we need to find a way to test it
* - JBehave tests are for the user story flows, here we only want to check with the complex queries, certain
* records are returned; performance can be verified in UAM.
*/
#RunWith(MockitoJUnitRunner.class)
public class ItemHistoryPersistenceServiceBeanDBIntegrationTest {
private static EntityManagerFactory factory;
private EntityManager realEntityManager;
private ItemHistoryPersistenceServiceBean serviceBean;
private Query<String> inputQuery;
#BeforeClass
public static void prepare() {
factory = Persistence.createEntityManagerFactory("test-item-history-service-bean");
}
#Before
public void setup() {
realEntityManager = factory.createEntityManager();
EntityManager spy = spy(realEntityManager);
serviceBean = new ItemHistoryPersistenceServiceBean();
try {
// inject the real entity manager, instead of using mocks
Field entityManagerField = serviceBean.getClass().getDeclaredField("entityManager");
entityManagerField.setAccessible(true);
entityManagerField.set(serviceBean, spy);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new AssertionError("should not reach here");
}
inputQuery = new Query<>();
inputQuery.setObjectId("itemId");
}
#After
public void teardown() {
realEntityManager.close();
}
#Test
public void findByIdAndToken_shouldReturnRecordsMatchingOnlyTokenFilter() {
try {
// when
List<ItemHistory> actual = serviceBean.findByIdAndToken(inputQuery);
// then
assertEquals(2, actual.size());
assertThat(actual.get(0).getItemPackageName(), anyOf(is("orgId 3.88"), is("orgId 3.99.3")));
assertThat(actual.get(1).getItemPackageName(), anyOf(is("orgId 3.88"), is("orgId 3.99.3")));
} catch (DataLookupException e) {
throw new AssertionError("should not reach here");
}
}
}