Hi all,
I got the the pilot test implementation in place to get the behavior tests
passing, i created this code review<https://source.openmrs.org/cru/CR-MOD-371>,
you can also view the code for the missing Test Provider i'm using for the
tests in svn
here<https://svn.openmrs.org/openmrs-modules/calculation/trunk/api/src/test/java/org/openmrs/calculation/provider/TestCalculationProvider.java>.
These are test implementations, but they do give a general idea of how
things are expected to be put together.
I did a couple of changes especially in the class hierarchy for the various
components, below is the summary of the structure:
*Calculations:*
interface Calculation{
}
abstract class BaseCalculation implements Calculation {
- Provides a default implementation for the single method which returns an
empty ParameterDefinitionSet
- This is the recommended class Calculations should extend
}
*Definitions:*
interface Definition{
}
interface ParameterDefinition extends Definition {
}
//-This is the recommend class ParameterDefinitions should extend
//-Adds fields including their getters and setters
abstract class BaseParameterDefinition implements ParameterDefinition {
}
//-Wrapper for a Hashet of Definitions and adds an extra method
class ParameterDefinitionSet extends HashSet<ParameterDefinition> {
getParameterByKey();
}
*Evaluators:*
public interface Evaluator {
}
public interface CalculationEvaluator extends Evaluator {
public CohortResult evaluate(Cohort cohort, Calculation calculation,
Map<String, Object> parameterValues,
CalculationContext context);
}
//-recommended class evaluators should extend
abstract class BaseCalculationEvaluator implements CalculationEvaluator {
}
*Provider:*
//-Shoud we have an abstract class for this?
//- When we start token registration, we can add a
DefaultCalculationProvider that looks up saved tokens from the DB
public interface CalculationProvider {
}
*Results:*
public interface Result {
}
//-Has a null value,
public class EmptyResult implements Result {
}
//-This is the recommend class Results should extend
//-Adds fields including their getters and setters.
abstract class BaseResult implements Result {
}
//-Superclass of results that need to keep track of when the evaluation of
the associated calculation occurred
public abstract class DateBasedResult extends BaseResult {
}
//-Provides a simple concrete implementation of a result that can be used
out of the box without creating another result class
public class DefaultResult extends BaseResult {
public DefaultResult(Object value, Calculation calculation) {
this(value, calculation, null);
}
public DefaultResult(Object value, Calculation calculation,
CalculationContext calculationContext) {
setValue(value);
setCalculation(calculation);
setCalculationContext(calculationContext);
}
}
public class CohortResult extends LinkedHashMap<Integer, Result> {
}
Added a createParameterDefinition() method to CalculationUtil to ease
creation of parameter defs, it takes different forms depending on the
fields you wish to get initiated.
*What is next?*
- Add tests for the CalculationContext and required paremeter definitions
and then implement them.
- Add tests for ResultUtil and implement its methods,
RestUtil.convert(Result r, Class<T> clazz) needs to handle wrapper classes
for primitives in a better way.
Does this sound right?, views are welcome.
Have a great weekend everyone
Wyclif
On Thu, Feb 16, 2012 at 8:21 PM, Burke Mamlin <[email protected]> wrote:
> Thanks for the update on your progress with Logic 2.0 (aka Calculation),
> Wyclif. Can we use calculationProvider.*getCalculation()* instead of
> calculationProvider.*getCalculationInstance()*?
>
> -Burke
>
>
> On Thu, Feb 16, 2012 at 7:03 PM, Wyclif Luyima <[email protected]> wrote:
>
>> Hi all,
>>
>> On Wednesday i completed the token registration CRUD methods and their
>> unit tests, i know we said this was for a later date, but i was already
>> done with 90% of the work, so i just decided to complete and commit it.
>>
>> Later yesterday(Wednesday) i wrote up the 3 tests outlined on the design
>> call along with a TestCalculationProvider and an AgeCalculator, i wrote
>> afew just for the start, i created a review for them where i added mike and
>> darius. Mike added some comments which i addressed this morning. Sorry I
>> got a little confused because darius said he preferred that i include the
>> tests in the email while preferred that i used crucible reviews probably we
>> need to decide on this.
>>
>> Today i have been coding up the the test calculation, evaluator,
>> provider, the evaluations service methods and wiring everything to get the
>> tests passing.
>>
>> The implementation for my TestCalculationProivider is that it has a
>> private map of calculationNames and Classes which takes the the form
>> '<String, Class<? extends Calculation>>', the map is populated from the
>> constructor of the provider. Typically when its getCalculationInstance()
>> method is called, it looks up the Class mapped to the key, creates an
>> instance of it and returns it.
>>
>> Below are the tests that i added and trying to get passing:
>>
>>
>> public void shouldCalculateThePatientAge() {
>> CalculationProvider p = new TestCalculationProvider();
>> Calculation ageCalculation = p.getCalculationInstance("age", null);
>> int patientId = 2;
>> int expected = Context.getPatientService().getPatient(patientId).getAge();
>> Assert.assertEquals(expected, service.evaluate(patientId,
>> ageCalculation).asType(Integer.class).intValue());
>> }
>> public void shouldCalculateThePatientAgeBasedOnContextualInfo() throws
>> ParseException {
>> CalculationProvider p = new TestCalculationProvider();
>> Calculation ageCalculation = p.getCalculationInstance("age", null);
>>
>> int patientId = 2;
>> Date date = new SimpleDateFormat(DATE_FORMAT).parse("2000-01-01");
>> CalculationContext ctxt = service.createCalculationContext();
>> ctxt.setIndexDate(date);
>> int expected =
>> Context.getPatientService().getPatient(patientId).getAge(date);
>> Assert.assertEquals(expected, service.evaluate(patientId, ageCalculation,
>> ctxt).asType(Integer.class).intValue());
>> }
>> public void
>> shouldCalculateThePatientAgeBasedOnContextualInfoAndParameterValues()
>> throws ParseException {
>> CalculationProvider p = new TestCalculationProvider();
>> Calculation ageCalculation = p.getCalculationInstance("age", null);
>> ParameterDefinitionSet pds =
>> ageCalculation.getParameterDefinitionsSet();
>> ParameterDefinition pd = pds.getParameterByKey("units");
>> Assert.assertNotNull(pd);
>> Assert.assertEquals(pd.getName(), "Units Of Age");
>> int patientId = 2;
>> Date date = new SimpleDateFormat(DATE_FORMAT).parse("2000-01-01");
>> CalculationContext ctxt = service.createCalculationContext();
>> ctxt.setIndexDate(date);
>> Map<String, Object> values = new HashMap<String, Object>();
>> values.put("units", "months");
>> Assert.assertEquals(296, service.evaluate(patientId, ageCalculation,
>> values, ctxt).asType(Integer.class).intValue());
>> }
>>
>>
>> Wyclif
>>
>
> ------------------------------
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
_________________________________________
To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to
[email protected] with "SIGNOFF openmrs-devel-l" in the body (not
the subject) of your e-mail.
[mailto:[email protected]?body=SIGNOFF%20openmrs-devel-l]