Sign in or 

| Version | User | Scope of changes |
|---|---|---|
| Apr 13 2009, 5:07 PM EDT (current) | jim.marion | 3637 words added, 8 photos added |
| Apr 13 2009, 3:02 PM EDT | jim.marion |
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.
| Listing 1 TestStringBufferTarget |
| import TTS_UNITTEST:TestBase; import ADS_LOGGER:StringBufferTarget; class TestStringBufferTarget extends TTS_UNITTEST:TestBase method TestStringBufferTarget(); method Run(); end-class; method TestStringBufferTarget %Super = create TTS_UNITTEST:TestBase("TestStringBufferTarget"); end-method; method Run /+ Extends/implements TTS_UNITTEST:TestBase.Run +/ Local ADS_LOGGER:StringBufferTarget &target = create ADS_LOGGER:StringBufferTarget(); &target.print("Hello World"); %This.AssertStringsEqual(&target.getBuffer(), "Hello World", "method failed"); end-method; |
| Listing 2 TestStringBufferTarget, version 2 |
| import TTS_UNITTEST:TestBase; import ADS_LOGGER:StringBufferTarget; class TestStringBufferTarget extends TTS_UNITTEST:TestBase method TestStringBufferTarget(); method Run(); end-class; method TestStringBufferTarget %Super = create TTS_UNITTEST:TestBase("TestStringBufferTarget"); %This.Msg("TestStringBufferTarget: constructor"); end-method; method Run /+ Extends/implements TTS_UNITTEST:TestBase.Run +/ %This.Msg("TestStringBufferTarget: Run"); Local ADS_LOGGER:StringBufferTarget &target = create ADS_LOGGER:StringBufferTarget(); Local string &message = "Hello World"; Local string &buffer; &target.print(&message); &buffer = &target.getBuffer(); %This.Msg("TestStringBufferTarget: printed :" | &message); %This.Msg("TestStringBufferTarget: buffer :" | &buffer); %This.AssertStringsEqual(&buffer, &message, "method failed"); end-method; |
| Listing 3 TestLogger Test Case |
| import TTS_UNITTEST:TestBase; import ADS_LOGGER:StringBufferTarget; import ADS_LOGGER:Logger; class TestLogger extends TTS_UNITTEST:TestBase method TestLogger(); method Run(); end-class; method TestLogger %Super = create TTS_UNITTEST:TestBase("TestLogger"); %This.Msg("TestLogger: constructor"); end-method; method Run /+ Extends/implements TTS_UNITTEST:TestBase.Run +/ %This.Msg("TestLogger: Run"); Local ADS_LOGGER:StringBufferTarget &target = create ADS_LOGGER:StringBufferTarget(); Local ADS_LOGGER:Logger &logger = create ADS_LOGGER:Logger(); Local string &message = "Hello World"; Local string &buffer; &logger.setTarget(&target); &logger.debug(&message); &buffer = &target.getBuffer(); %This.Msg("TestLogger.Run: printed: " | &message); %This.Msg("TestLogger.Run: buffer: " | &buffer); %This.AssertStringsEqual(&buffer, &message, "method failed"); end-method; |
| Listing 4 Logger Implementation |
| import ADS_LOGGER:Target; class Logger method debug(&message As string); method setTarget(&target As ADS_LOGGER:Target); private instance ADS_LOGGER:Target &target_; end-class; method debug &target_.print(&message); end-method; method setTarget &target_ = &target end-method; |
| Listing 5 TestLogger Test Case that Tests Configuration |
| import TTS_UNITTEST:TestBase; import ADS_LOGGER:StringBufferTarget; import ADS_LOGGER:Logger; class TestLogger extends TTS_UNITTEST:TestBase method TestLogger(); method Run(); private method Run_OnTest(); method Run_OffTest(); Constant &MESSAGE = "Hello World"; end-class; method TestLogger %Super = create TTS_UNITTEST:TestBase("TestLogger"); %This.Msg("TestLogger: constructor"); end-method; method Run /+ Extends/implements TTS_UNITTEST:TestBase.Run +/ %This.Msg("TestLogger: Run"); %This.Msg("TestLogger: Turn on logging"); SQLExec("UPDATE PS_ADS_LOG_CONFIG SET FLAG = 'Y'"); %This.Run_OnTest(); %This.Msg("TestLogger: Turn off logging"); SQLExec("UPDATE PS_ADS_LOG_CONFIG SET FLAG = 'N'"); %This.Run_OffTest(); end-method; method Run_OnTest %This.Msg("TestLogger.Run_OnTest"); Local ADS_LOGGER:StringBufferTarget &target = create ADS_LOGGER:StringBufferTarget(); Local ADS_LOGGER:Logger &logger = create ADS_LOGGER:Logger(); &logger.setTarget(&target); &logger.debug(&MESSAGE); %This.AssertStringsEqual(&target.getBuffer(), &MESSAGE, "method failed"); end-method; method Run_OffTest %This.Msg("TestLogger.Run_OffTest"); Local ADS_LOGGER:StringBufferTarget &target = create ADS_LOGGER:StringBufferTarget(); Local ADS_LOGGER:Logger &logger = create ADS_LOGGER:Logger(); &logger.setTarget(&target); &logger.debug(&MESSAGE); |
| Listing 6 Logger class that implements the on/off behavior |
| import ADS_LOGGER:Target; class Logger method Logger(); method debug(&message As string); method setTarget(&target As ADS_LOGGER:Target); private instance ADS_LOGGER:Target &target_; instance boolean &isOn; end-class; method Logger Local string &flag; SQLExec("SELECT FLAG FROM PS_ADS_LOG_CONFIG", &flag); If (&flag = "Y") Then &isOn = True; End-If; end-method; method debug /+ &message as String +/ If (&isOn) Then &target_.print(&message); End-If; end-method; method setTarget /+ &target as ADS_LOGGER:Target +/ &target_ = &target end-method; |
| Listing 7 MesageBoxTarget class |
| import ADS_LOGGER:Target; class MessageBoxTarget implements ADS_LOGGER:Target method print(&message As string); end-class; method print /+ &message as String +/ /+ Extends/implements ADS_LOGGER:Target.print +/ MessageBox(0, "", 0, 0, &message); end-method; |
| Listing 8 MesageBoxTarget test case |
| import TTS_UNITTEST:TestBase; import ADS_LOGGER:MessageBoxTarget; import ADS_LOGGER:Logger; class TestMessageBoxTarget extends TTS_UNITTEST:TestBase method TestMessageBoxTarget(); method Setup(); method Run(); method Teardown(); private instance string &flag_; end-class; method TestMessageBoxTarget %Super = create TTS_UNITTEST:TestBase("TestMessageBoxTarget"); %This.Msg("TestMessageBoxTarget: constructor"); end-method; method Setup /+ Extends/implements TTS_UNITTEST:TestBase.Setup +/ Local string &flag; %This.Msg("TestMessageBoxTarget: Setup"); SQLExec("SELECT FLAG FROM PS_ADS_LOG_CONFIG", &flag); &flag_ = &flag; end-method; method Run /+ Extends/implements TTS_UNITTEST:TestBase.Run +/ %This.Msg("TestMessageBoxTarget: Run"); SQLExec("UPDATE PS_ADS_LOG_CONFIG SET FLAG = 'Y'"); Local ADS_LOGGER:Logger &logger = create ADS_LOGGER:Logger(); &logger.setTarget(create ADS_LOGGER:MessageBoxTarget()); &logger.debug("Hello World"); end-method; method Teardown /+ Extends/implements TTS_UNITTEST:TestBase.Teardown +/ Local string &flag = &flag_; %This.Msg("TestMessageBoxTarget: Teardown"); SQLExec("UPDATE PS_ADS_LOG_CONFIG SET FLAG = :1", &flag); end-method; |