To see how you could start using PODAM straight away, please refer to the usage page.
PodamFactory factory = new PodamFactoryImpl(); //This will use the default Random Data Provider Strategy Pojo myPojo = factory.manufacturePojo(Pojo.class);
PODAM allows users to customise the way data are assigned in several ways:
The default strategy for PODAM is Random values. However users can define their own global strategy by providing an implementation of the DataProviderStrategy interface, as follows:
DataProviderStrategy strategy = new MyDataProviderStrategy(); PodamFactory factory = new PodamFactoryImpl(strategy); Pojo myPojo = factory.manufacturePojo(Pojo.class);
PODAM allows also users to define data strategies at the attribute level: this includes the capability to define custom strategies for elements and keys in collections, maps and arrays. In order to define an attribute-level strategy, users will need to:
Example:
@PodamStrategyValue(PostCodeStrategy.class) private String postCode; @PodamStrategyValue(MyBirthdayStrategy.class) private Calendar myBirthday;
In this example I defined two attribute-level strategies:
The PostCodeStrategy class looks like the following:
/**
*
*/
package uk.co.jemos.podam.test.strategies;
import uk.co.jemos.podam.api.AttributeStrategy;
import uk.co.jemos.podam.exceptions.PodamMockeryException;
import uk.co.jemos.podam.test.utils.PodamTestConstants;
/**
* A test strategy to manufacture UK-like post codes.
*
* @author mtedone
*
*/
public class PostCodeStrategy implements AttributeStrategy<String> {
/**
* It returns an English post code.
* <p>
* This is just an example. More elaborated code could the implemented by
* this method. This is just to proof the point.
* </p>
*
* {@inheritDoc}
*/
public String getValue() throws PodamMockeryException {
return PodamTestConstants.POST_CODE;
}
}
There is nothing special about the above class: it's job is just to provide a value of the right type.
The MyBirthdayStrategy class looks like the following:
/**
*
*/
package uk.co.jemos.podam.test.strategies;
import java.util.Calendar;
import uk.co.jemos.podam.api.AttributeStrategy;
import uk.co.jemos.podam.exceptions.PodamMockeryException;
import uk.co.jemos.podam.test.utils.PodamTestUtils;
/**
* An attribute strategy which returns a Calendar object set with my DOB.
*
* @author mtedone
*
*/
public class MyBirthdayStrategy implements AttributeStrategy<Calendar> {
/**
* It returns a {@link Calendar} object set with the exact date of my
* birthday.
*
* {@inheritDoc}
*/
public Calendar getValue() throws PodamMockeryException {
Calendar myBirthday = PodamTestUtils.getMyBirthday();
return myBirthday;
}
}
The capability to customise the strategy PODAM uses to fill attribute data is extended to container-like data structures, such as Collections, Maps and Arrays; however for these data structures use the @PodamCollection annotation. Please refer to The annotation page for more details.
Example on how to use PODAM custom attribute strategy to fill collection elements:
@PodamCollection(nbrElements = 2, collectionElementStrategy = MyBirthdayStrategy.class) private List<Calendar> myBirthdays = new ArrayList<Calendar>();
Example on how to use PODAM custom attribute strategy to fill Map keys and elements. Please note that @PodamCollection offers also the possibility to define a strategy to set the values for keys in a Map, through the mapKeyStrategy attribute:
@PodamCollection(nbrElements = 2, mapElementStrategy = MyBirthdayStrategy.class) private Map<String, Calendar> myBirthdaysMap = new HashMap<String, Calendar>();
Example on how to use PODAM custom attribute strategy to fill array elements:
@PodamCollection(nbrElements = 2, collectionElementStrategy = MyBirthdayStrategy.class) private Calendar[] myBirthdaysArray;
PODAM will use the MyBirthdayStrategy to set the value for the two array elements.
Primitive and Wrapper type values can be customised through annotations.
@PodamDoubleValue(minValue = PodamTestConstants.NUMBER_DOUBLE_MIN_VALUE, maxValue = PodamTestConstants.NUMBER_DOUBLE_MAX_VALUE) private double doubleFieldWithMinAndMaxValue;
Please note that by contract (DataProviderStrategy) min and max values are inclusive.
For a full list of supported annotations, please refer to the Annotations page.
To know more about how PODAM works, please refer to the The walk-through example page or to the Corner Cases page on the left menu.
Sometimes you may want to manufacture a generic type directly without a wrapper class or a subclass.
As you should have noticed, the manufacturePojo method of the PodamFactory interface can take some additional parameters through varargs. This is a way to allow the definition of the generic types for a given class.
The following class is an example of a generic POJO:
public class GenericPojo<F, S> {
private F firstValue;
private S secondValue;
@PodamCollection(nbrElements = 2)
private List<F> firstList;
@PodamCollection(nbrElements = 2)
private S[] secondArray;
@PodamCollection(nbrElements = 2)
private Map<F, S> firstSecondMap;
... getter, setters and toString
}Now imagine that you want an instance of this class defining F and S as Double and String respectively. This is how it should be done:
GenericPojo pojo = factory.manufacturePojo(GenericPojo.class, Double.class, String.class);
As you can see, the first class is the POJO to be manufactured (GenericPojo), and the subsequent classes are the type parameters to be used for this GenericPojo instance.
This is the result of the call above:
GenericPojo [
firstValue=0.03181392348712919,
secondValue=L4OicBAhKY,
firstList=[0.770082469177622, 0.7924208229673068],
secondArray=[8EsGFHtwwE, Zqz8B_4oAr],
firstSecondMap={0.778926356384843=sl4FxQIEYe, 0.2909259461070528=j8mlZshNsv}
]It is also possible to specify some complex nested generic types like GenericPojo<GenericPojo<String, Long>, Map<Integer, List<Boolean>>> using the uk.co.jemos.podam.api.PodamParameterizedType class as in the following example:
ParameterizedType stringLongGenericPojoType =
new PodamParameterizedType(GenericPojo.class, String.class, Long.class);
ParameterizedType IntegerBooleanListMapType =
new PodamParameterizedType(Map.class,
Integer.class,
new PodamParameterizedType(List.class, Boolean.class));
GenericPojo<GenericPojo<String, Long>, Map<Integer, List<Boolean>>> pojo =
factory.manufacturePojo(GenericPojo.class, stringLongGenericPojoType, IntegerBooleanListMapType);Running the code above the following result is produced:
GenericPojo [
firstValue=GenericPojo [
firstValue=e0NI7ZnKfW,
secondValue=1340165351073,
firstList=[2UlUwNJdOS, bZ7X0KZWtV],
secondArray=[1340165351073, 1340165351073],
firstSecondMap={QiB36seL99=1340165351072, Dk_KwHCGOq=1340165351072}
],
secondValue={2081811337=[true]},
firstList=[
GenericPojo [
firstValue=ECNfFuF6WM,
secondValue=1340165351067,
firstList=[QfZXnqOk1N, HDAGfxdat0],
secondArray=[1340165351067, 1340165351067],
firstSecondMap={UgJ4VNvro_=1340165351067, 5NGtW0hH0h=1340165351067}
],
GenericPojo [
firstValue=kHryFVavEn,
secondValue=1340165351070,
firstList=[wAKe40d3zO, OH8q03P9Cw],
secondArray=[1340165351070, 1340165351070],
firstSecondMap={LhRoWR2DNX=1340165351068, zg0IAN4ZZ5=1340165351068}
]
],
secondArray=[{2115657799=[true, true], -1507554610=[true, true]}, {1990372468=[true, true], -340173617=[true, true]}],
firstSecondMap={
GenericPojo [
firstValue=WeEDkbr2pc,
secondValue=1340165351058,
firstList=[0TRSKWur8n, vbIptzObXA],
secondArray=[1340165351057, 1340165351057],
firstSecondMap={49wLsEiuip=1340165351056, LGIUi7CptX=1340165351056}
] = {1126207473=[true, true], -1973087621=[true, true]},
GenericPojo [
firstValue=2RtNOrjgjZ,
secondValue=1340165351064,
firstList=[l1S7URCgFT, ntoKQnI1Kj],
secondArray=[1340165351064, 1340165351064],
firstSecondMap={F0gqzGJMZL=1340165351061, vXdlU9NCfR=1340165351061}
] = {-485029362=[true, true], 609129754=[true, true]}
}
]You can also use PODAM with Spring:
# Define your Spring app context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- The definition of the default strategy -->
<bean id="myDataProviderStrategy"
class="uk.co.jemos.podam.api.MyDataProviderStrategy"
factory-method="getInstance" />
<!-- The definition of PODAM factory -->
<bean id="podamFactory" class="uk.co.jemos.podam.api.PodamFactoryImpl">
<constructor-arg index="0" ref="myDataProviderStrategy" />
</bean>
</beans>
# Use Podam Factory in your code
/**
*
*/
package uk.co.jemos.podam.test.unit.integration;
import javax.annotation.Resource;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import uk.co.jemos.podam.api.PodamFactory;
import uk.co.jemos.podam.test.dto.SimplePojoToTestSetters;
/**
* @author mtedone
*
*/
@ContextConfiguration(locations = {"classpath:podam-test-appContext.xml"})
public class PodamFactoryInjectionIntegrationTest
extends AbstractJUnit4SpringContextTests {
/** The Podam Factory */
@Resource
private PodamFactory factory;
@Before
public void init() {
Assert.assertNotNull("The PODAM factory cannot be null!", factory);
Assert.assertNotNull("The factory strategy cannot be null!",
factory.getStrategy());
}
@Test
public void testSimplePojo() {
SimplePojoToTestSetters pojo = factory
.manufacturePojo(SimplePojoToTestSetters.class);
Assert.assertNotNull("The pojo cannot be null!", pojo);
...etc
}
}Please note that the data provider strategy cannot be changed upon instantiation. If you want to use a different data provider strategy, you'll need to create a new instance of PodamFactory. This has been decided to preserve thread-safety and immutability of PodamFactory.
By default PODAM assigns random values to all its types. However, PODAM can be extended by providing a custom implementation of the uk.co.jemos.podam.api.DataProviderStrategy interface. Please note that methods which return a numeric value between ranges should consider the ranges inclusive, as documented in the interface Javadoc.
PODAM uses the uk.co.jemos.podam.api.RandomDataProviderStrategy class as default Data Provider implementation.
To know more about how PODAM works, please refer to the The walk-through example page or to the Corner Cases page on the left menu.