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]

Reply via email to