CSC/ECE 517 Spring 2013/OSS M604: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 62: Line 62:
The framework used here for testing is [http://junit.org/ JUnit4]
The framework used here for testing is [http://junit.org/ JUnit4]
All the code for the test functions are at [https://github.com/ashrayn/openmrs-module-m604/blob/master/changerelationships/api/src/test/java/org/openmrs/module/changerelationships/api/ChangeRelationshipsServiceTest.java ChangeRelationshipsServiceTest.java]
All the code for the test functions are at [https://github.com/ashrayn/openmrs-module-m604/blob/master/changerelationships/api/src/test/java/org/openmrs/module/changerelationships/api/ChangeRelationshipsServiceTest.java ChangeRelationshipsServiceTest.java]
The test class consists of simple unit tests to test the working of each function used in the ChangeRelationshipService class.
The test class consists of simple unit tests to test the working of each function used in the ChangeRelationshipService class.
===Setup()===
===Setup()===
The setup() function is the one responsible for setting up the background before testing all the functions. It initializes all the objects used for testing later. The code for setup() is as  
The setup() function is the one responsible for setting up the background before testing all the functions. It initializes all the objects used for testing later. The code for setup() is as  
personService = Context.getPersonService();
 
this.testCangeRelationshipService = Context.getService(ChangeRelationshipsService.class);
this.testPeople = new ArrayList();
this.testRelations = new ArrayList();
this.testRelationshipTypes = new ArrayList();
===Test Data===
===Test Data===
The createTestPeopleAndRelations() functions is similar to the setup function, as it too sets up the background data required for some of the testing, but since not all of the unit tests require a sample data, they are in a separate function and only those functions that require the data call them. Code snippet for the function :   
The createTestPeopleAndRelations() functions is similar to the setup function, as it too sets up the background data required for some of the testing, but since not all of the unit tests require a sample data, they are in a separate function and only those functions that require the data call them. Code snippet for the function :   
createTestPeopleAndRelations(){
 
testPeople.add(createAndSavePerson("Person5", "For5", "Testing5", "Male", 1967, 8,3 ));
testRelationshipTypes.add(createNewRelationType("TestRType1", "TestRType2"));
testRelations.add(new Relationship(testPeople.get(0), testPeople.get(1), testRelationshipTypes.get(0) ));
}


Similarly the function deleteDataCreatedForTests() is a cleanup function that removes all the data created specifically for the tests. Code snippet for the function :  
Similarly the function deleteDataCreatedForTests() is a cleanup function that removes all the data created specifically for the tests. Code snippet for the function :  
deleteDataCreatedForTests(){
 
personService.purgeRelationship(rs);
personService.purgeRelationshipType(rt);
personService.purgePerson(p);
}


The functions createNewRelationType() and createAndSavePerson() are helper functions for the test data setup functions mentioned above. The createAndSavePerson() saves each person to the database while the  createNewRelationType() function saves each new relationship type tothe database
The functions createNewRelationType() and createAndSavePerson() are helper functions for the test data setup functions mentioned above. The createAndSavePerson() saves each person to the database while the  createNewRelationType() function saves each new relationship type tothe database
Line 89: Line 78:
===Unit test : shouldSetupContext() and shouldSetupPersonService()===
===Unit test : shouldSetupContext() and shouldSetupPersonService()===
Makes sure that the service objects are initialized and not null.
Makes sure that the service objects are initialized and not null.
public void shouldSetupContext() {
 
assertNotNull(Context.getService(ChangeRelationshipsService.class));
}
public void shouldSetupPersonService(){
setup();
assertNotNull(personService);
}


===Unit test : getPersonObjectFromInputnameTest ===
===Unit test : getPersonObjectFromInputnameTest ===

Revision as of 22:09, 21 March 2013

OpenMRS Change Patient Relationships

README

The design document for the project can be found at [1]

The project is currently hosted at a long term VCL image found at [2]

The code for our module is hosted on github at [3]

To Use:

  1. Login with user:Admin password:Admin123.
  2. Click the 'Administration' button in the top-right corner.
  3. In the bottom-right corner, under 'patients' there should be a link for "change patient relationships".
  4. Click on the 'change patient relationships' link
  5. The content of the change patient relationships module should be displayed.

To see a list of possible patients, it may be useful to open a separate tab with the 'Find/Create Patient" menu from the main menu bar.

Writing Exercise 2

Design Overview of the Module

OpenMRS modules utilize a modified Spring MVC framework [4]. The skeleton for the module is first generated using convenient maven[5] artifacts provided here [6].

The 'change patient relationships' module utilizes 5 basic files.

  1. The main page is a .jsp [7] page, the code can be found at [8].
  2. This .jsp page is linked to a spring annotated controller [9], the code can be found at [10]. The annotated controller maps the manage.jsp form actions using the '@RequestMapping' annotations. This pattern can be observed by viewing the manage.jsp code and comparing the <form> tags to the @RequestMapping annotations in the java code.
  3. The controller along with the spring framework link the form actions from the 'manage.jsp' page to java objects defined in the following .java files. [11] and [12]
  4. The module utilizes OpenMRS's services infrastructure to create services with the following code [13]. The services found within this class are retrieved from the OpenMRS context object inside of the above controller code (#2). The ChangePatientRelationshipsServiceImpl.java class utilizes OpenMRS database APIs [14] to actually change the patient data in the OpenMRS database.

The entire module is packaged in an OpenMRS .omod file using maven and pre-created packaging scripts. The .omod file can be found here [15] and installed into any OpenMRS server using the 'Administration'>Manage modules page.

Object-Oriented Design Principles Used

Encapsulation
There were several instances of encapsulation used through out our implementation code in the OpenMRS module. For example, to get access to relationships between people in the database in OpenMRS, we first had to use the Context class to get a PersonService object type and then use that object type to access a list of relationships:

personService = Context.getPersonService();

Here, getPersonService() is a static method in class Context that doesn't require instantiating a Context object to call the method. getPersonService() can be directly used as a class method without having to know the details of how the method has been implemented and designed.
Another example is making helper methods and instance variables private.

private Person getPersonOut(List<Relationship> relationshipList, String nameOut)

This is a helper method to the changePatientRelationships() method that helps locate the Person object for updating the patient relationship. As it is not directly used in the manage.jsp page for the user-interface, it is made private to restrict access to it.

private ChangeRelationshipsDAO dao;
private List<Person> people;
private List<Relationship> allRelatedPeople;
private List<RelationshipType> existingRelationshipTypes;
private int noOfRelatedPeople;

These instance variables are also made private in our module class to prevent the potential corruption of data if they were to be accessed publicly.

Open-Closed Principle
In the OpenMRS module, existing classes that had already been tested were not modified, which exemplifies the open-closed principle [16]. This module is an extension of the OpenMRS functionality. Our ChangeRelationshipsServiceImpl class is an added class to specifically add the functionality of being able to update the relationships of several patients at one time. Specifically, in our the ChangeRelationshipServiceImpl, we extend the class BaseOpenmrsService to implement the new functionality:

public class ChangeRelationshipsServiceImpl extends BaseOpenmrsService implements ChangeRelationshipsService


Testing

The framework used here for testing is JUnit4 All the code for the test functions are at ChangeRelationshipsServiceTest.java

The test class consists of simple unit tests to test the working of each function used in the ChangeRelationshipService class.

Setup()

The setup() function is the one responsible for setting up the background before testing all the functions. It initializes all the objects used for testing later. The code for setup() is as

Test Data

The createTestPeopleAndRelations() functions is similar to the setup function, as it too sets up the background data required for some of the testing, but since not all of the unit tests require a sample data, they are in a separate function and only those functions that require the data call them. Code snippet for the function :


Similarly the function deleteDataCreatedForTests() is a cleanup function that removes all the data created specifically for the tests. Code snippet for the function :


The functions createNewRelationType() and createAndSavePerson() are helper functions for the test data setup functions mentioned above. The createAndSavePerson() saves each person to the database while the createNewRelationType() function saves each new relationship type tothe database

Unit test : shouldSetupContext() and shouldSetupPersonService()

Makes sure that the service objects are initialized and not null.


Unit test : getPersonObjectFromInputnameTest

Asserts that the function getPersonObjectFromInputname() returns exactly one person in case a record matching the given name is found, else returns a record not found error

Unit test : findRelationshipTypeFromInputTest()

Asserts that the function findRelationshipTypeFromInputTest() returns the relationship type in case a record matching the given type name is found, else returns a record not found error.

unit Test : numberOfRelationshipGivenPersonAndRelationshipTypeTest()

Tests wether the function numberOfRelationships() returns the right number of related people given the name of a person and the relationship type.

unit Test : numberOfRelationshipsWhenAllSelected()

In case the user chose to change all the relationships for a given person, this test case checks to see if the function numberOfRelationships() returns the right number of people related to the given person in any possible way.