PSUNIT – a few odds and ends

This is a quick follow-up to the earlier posts I’ve made about PSUnit.  To get more familiarity with the tool I had started to build tests against a piece of a project I had just finished up and moved into production.

I was confident the code in the project was good as I had run test files against it continuously as I was coding.

A PSUnit test found a bug.

Ouch.  Glad I found it and not someone else, and it’s good to have found it now while other parts of the project are still outstanding.  And I’m kicking myself for not having used the PSUnit tool while I was writing the code for the project.

One more thing.  I’ve zipped up a project based on the code provided in the readme file you get if you install the PSUnit tool.  It’s available here.  I created it going thru the readme step by step – the code in the zip file is the result.  It was built using PTools 8.51.

PSUnit – Adding Tests

In my previous post I showed the various Assert tests that come with the PSUnit project.  I decided to add another test to the code.

There is only a single boolean Assert test – which checks if the value is True.  But there are times when a boolean False is the correct response.  So I added an AssertFalse test to the code:

AssertFalse(&isTrue As boolean, &onFail As string);

If the value in &isTrue is True, then the test fails.

Clearly you need to have pulled the PSUnit project into a PeopleSoft database instance and created the tables.  From here, start App Designer and open the TTS_UNITTEST Application Package.

You want to click on the TestBase app class and view the PeopleCode associated with it.

In the class TestBase I added the method definition:

  • method AssertFalse(&isTrue As boolean, &onFail As string);

Then I added the code for the method:

/* This was added to test for boolean False values */
method AssertFalse
   /+ &isTrue as Boolean, +/
   /+ &onFail as String +/
  
   If (&isTrue) Then
      throw create TTS_UNITTEST:Exceptions:AssertFailed(&onFail);
   End-If;
  
end-method;

How is this useful?  Let’s take an example of checking for a valid emplid.  I have a method:

method isEmplidValid
   /+ &empID as String +/
   /+ Returns Boolean +/
   Local boolean &_rtn = False;
   Local string &_msg;
   Local SQL &_sql;
  
   &_sql = GetSQL(SQL.VALID_EMPLID_CHECK, &empID);
   While &_sql.Fetch(&_msg)
      If &_msg = “X” Then
         &_rtn = True;
      End-If;
   End-While;
  
   &_sql.Close();
  
   Return &_rtn;
  
end-method;

The SQL definition is fairly simple:

SELECT ‘X’
  FROM PS_JOB A
 WHERE A.EMPLID = :1
   AND A.EFFDT = (
 SELECT MAX(A1.EFFDT)
  FROM PS_JOB A1
 WHERE A1.EMPLID = A.EMPLID
   AND A1.EFFDT <= SYSDATE)
   AND A.EFFSEQ = (
 SELECT MAX(A2.EFFSEQ)
  FROM PS_JOB A2
 WHERE A2.EMPLID = A.EMPLID
   AND A2.EFFDT = A.EFFDT)

This method validates emplids against the JOB table.  A return of False is a correct data state in this instance.  The Assert test would throw an error even though I should expect some values to return as false.

Next I create the tests.  I have two arrays – one has valid emplids for the organization; the other has invalid emplids.  I can now do both positive and negative testing with this method:

method TestIsEmplidValid
   %This.Msg(“TestFieldsCheckField: TestCheckChars”);
   Local boolean &rtn;
   Local integer &i;
   &rtn = False;
   Local PKGE:EMPLOYEE:CheckEmplid &target = create PKGE:EMPLOYEE:CheckEmplid();
  
   /* First the positive test */
   For &i = 1 To &_EmplidArray.Len;
      %This.Msg(“TestIsEmplidValid: Assert Test Value: ” | &_EmplidArray [&i]);
      &rtn = &target.isEmplidValid(&_EmplidArray [&i]);
      %This.Assert(&rtn, “Assert method failed”);
   End-For;
  
   /* Then the negative test */
   For &i = 1 To &_BadEmplidArray.Len;
      %This.Msg(“TestIsEmplidValid: AssertFalse Test Value: ” | &_BadEmplidArray [&i]);
      &rtn = &target.isEmplidValid(&_BadEmplidArray [&i]);
      %This.AssertFalse(&rtn, “AssertFalse method failed”);
   End-For;
  
end-method;

Having the AssertFalse method allows me to confirm that my checking routine is working correctly.  I’m able to test that my program can gracefully handle invalid/incorrect data.

PSUnit Assert Tests

PSUnit provides a series of Assert tests.  In the article provided as part of the zipped download Jim Marion goes step by step into the process of creating a test.  However he only uses a single test: AssertStringsEqual.

I dug into the code and listed the tests you can do with PSUnit.

Assert(&isTrue As boolean, &onFail As string);

If the value in &isTrue is False, then the test fails.  From the program notes:

The first argument must be a boolean expression, which should evaluate to true.  If false, PSUnit throws an exception to indicate that the test failed.  The test runner catches the exception, marks the test as having failed, and continues on to the next test.

AssertStringsEqual(&str1 As string, &str2 As string, &onFail As string);

AssertStringsDiffer(&str1 As string, &str2 As string, &onFail As string);

AssertNumbersEqual(&num1 As number, &num2 As number, &onFail As string);

AssertNumbersDiffer(&num1 As number, &num2 As number, &onFail As string);

AssertDatesEqual(&date1 As date, &date2 As date, &onFail As string);

AssertDatesDiffer(&date1 As date, &date2 As date, &onFail As string);

AssertRowsetValuesEqual(&rs1 As Rowset, &rs2 As Rowset, &onFail As string);

Method first checks the ActiveRowCounts between the two rowsets.

Then the method tests that both rowsets come from the same Record.

Finally the method tests the fields in each row of each rowset for equality.

If an Assert test fails, the exception text which includes whatever message you pass on as part of the variable  &onFail gets sent to Class AssertFailed; which then calls the PeopleCode function CreateException.

PeopleSoft PSUnit

I first came across PSUnit in Jim Marion’s book PeopleSoft PeopleTools Tips & Techniques.  It’s a different tool from Test Framework – and you should consider it as complementary to PTF.

Jim has a write up of it here; there is another small explanation of it here.  Both articles give a link to the code, or you can get it here.

PSUnit is a Test Driven Development tool.  With Test Framework you code, create a page, and then put your page into a component.  The component gets applied to a menu which then get set into the registry.

With PSUnit you create a test framework Application Package, which gets plugged into an already existing test page.  Better yet – while Test Framework can help to point out where a transaction throws an exception, PSUnit lets you dig further and find out why.

From Jim Marion’s blog piece PSUnit Unit Testing Framework:

You, the developer, receive a notification from a user that page X of component COMP_X is calculating the wrong values. The user informs you that the calculation and error occur when he/she clicks save. From this information, you speculate that the calculation happens in the SavePreChange or SavePostChange event of the component or some record used in the component. Unfortunately, you are not familiar with this page or component.

With a PeopleCode trace, you are able to identify six potential events. You notice that these events call FUNCLIB’s and App Classes creating a horrendously deep call stack. From what you have in front of you, it is obvious that a quick review of this 3,000+ line trace file won’t provide an easy solution.

At this point you have several options:

Continue to treat COMP_X as a black box, investigating it from the outside.

Dig into the code and speculate as to its purpose.

Configure app server debugging and step through the deep call stack.

Start adding MessageBox statements to the delivered code so you can interrogate the state of the application as it runs.

We will choose the final option, the MessageBox option. Yes, this will require us to modify delivered code, but this modification should have no impact on the behavior of the code. The modification doesn’t concern me as much as forgetting to delete one of those MessageBox statements after I find and fix the problem. And then, once I find the correct combination of MessageBox statements to show the problematic data or logic, I hate to delete them, knowing I may have to visit this code at a future date (sooner then I want, but far enough in the future that I’ve already forgotten how I solved the problem). Wouldn’t it be nice if, once you found the appropriate combination of logging statements, you could just leave them in the code?

You should read the entire post.  I’ll list the various Assert tests that are available in another post.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: