Partager via


SysTest part I.: Assertions and test classes

In the next series of posts I will demonstrate and explain some of the basic as well as some more advanced features of SysTest.

Test classes

Let's begin with a very simple test. To create a test, derive a class from SysTestCase class. This is all that is needed for SysTest to be able to run tests from this class. This class might have many different methods. How does SysTest know what are the main methods that should be run as unit tests?

SysTest is looking for all the methods with the following signature:

  public void test*()

All these methods are recognized as unit tests and executed.

Assertions

SysTest offers a wide range of assert methods for you to use in your tests. You can see them all in SysTestAssert class.

Method Meaning
assertEquals asserts that the two parameters are equal; when the parameters are classes implementing "equal" method then this method is called to compare them, otherwise they are compared using == operator
assertNotEqual oposite to assertEquals
assertSame compares the parameters using == operator
assertNotSame oposite to assertSame
assertRealEquals compares two real values with a provided delta; therefore if you pass number1, number2 and delta, then the assert passes when | number1 - number2 | <= delta
assertNull assert fails when the parameter is not null
assertNotNull oposite to assertNull
assertTrue assert fails when the parameter is evaluated as false
assertFalse assert fails when the parameter is evaluated as true

The class has two additional public members.

Method Meaning
info logs an information message (used for debug trace for example)
fail logs an error message and fails the current test

Let's now write a simple set of tests exercising these assert methods. The following two tests call assertEquals to verify string conversion functions:

  public void testConversionFromString()
 {
    this.assertEquals(123, str2int('123'));
    this.assertEquals(1234.56, str2num('1234.56'));
    this.assertEquals(28\7\1973, str2date('28.7.1973', 123));
 }
 
 public void testConversionToString()
 {
    this.assertEquals('123', int2str(123));
    this.assertEquals('1,234.56', num2str(1234.56, -1, 2, 1, 2));
    this.assertEquals('28.7.1973', date2str(28\07\1973, 123, 1, 2, 1, 2, 4));
 }

See that assertEquals takes anytype as a parameter and thus you can compare strings as well as dates and other base types.

Let's now try to compare objects. Assume we have the following class:

 public class ComparableObject
 { 
  str name;
   
  public str parmName(str _value = name)
  {
    ;
    name = _value;
    return name;
  }
   
  public static ComparableObject construct()
  {
    ;
    return new ComparableObject();
  }
  protected void new()
  {
    ;
    name = '';
  }
 
  public boolean equal(ComparableObject _compareWith)
  {
    ;
    return (strcmp(this.parmName(), _compareWith.parmName()) == 0);
  }
  public str toString()
  {
    ;
    return name;
  }
 }

Now we can compare instances of this class using our next test:

  void testObjectComparison()
 {
    #define.name('David Pokluda')
    
    ComparableObject object1 = ComparableObject::construct();
    ComparableObject object2 = ComparableObject::construct();
    ;
    object1.parmName(#name);
    object2.parmName(#name);
    
    this.assertEquals(#name, object1.parmName());
    this.assertEquals(#name, object2.parmName());

    this.assertNotSame(object1, object2);
    this.assertEquals(object1, object2);
 }

See that assertSame would fail because those are different instances but assertEqual passes just right. That's because assertEquals is calling object's equal method to determine whether the instances are equal or not.

Note: You might also notice how SysTest reports failures on objects. Try to change the call from assertNotSame to assertSame. The framework reports something like this:

 [mySimpleTests.testObjectComparison] Failure: Assertion failed! 
(Expected: David Pokluda; Actual: David Pokluda)

How does the framework know that the expected value is "David Pokluda"? Notice that I have added toString method to my object. That's what SysTest calls (when available) to report the expected and actual value for objects.

Let's now try the last two methods, info and fail.

  public void testInfo()
 {
    ;
    this.info('This is a debug message.');
 }
 
 public void testFail()
 {
    ;
    this.fail('Failed the test by calling fail method.');
 }

When you run the tests you will see that testFail failed and the message would be the one provided by us when calling fail method. But where is our info message?

If you use toolbar to run tests (Tools > Development Tools > Unit Test > Show toolbar) then in case of errors/failures, the error messages are displayed in the Infolog. Info messages are ignored in toolbar. If you want to see them you have to either use other test runner (we will cover this topic hopefully sometime later -- if requested) or you write a simple runner yourself. The following job would run our tests:

  static void RunMySimpleTests(Args _args)
 {
    SysTestSuite suite = new SysTestSuite(classstr(MySimpleTests));
    SysTestResult result = new SysTestResult();
    ;
    suite.run(result);
    print result.getSummary();
    pause;
 }

There are different listeners (we will cover this in detail sometime later). Toolbar runner is using a modification of SysTestListenerInfolog that displays only error messages. If you want to see all the messages use either SysTestListenerPrint or SysTestListenerInfolog. Or use both. Do you see how flexible this is?

  static void RunMySimpleTests(Args _args)
 {
    SysTestSuite suite = new SysTestSuite(classstr(MySimpleTests));
    SysTestResult result = new SysTestResult();
    ;
    result.addListener(new SysTestListenerPrint());
    suite.run(result);
    print result.getSummary();
    
    pause;
 } 

Don't worry for now what all those objects mean, just use this sample as a template for your own jobs. I prefer instead of jobs to add this to the test as main method:

  public static void main(Args _params)
 {
    SysTestSuite suite = new SysTestSuite(classstr(MySimpleTests));
    SysTestResult result = new SysTestResult();
    ;
    result.addListener(new SysTestListenerPrint());
    suite.run(result);
    print result.getSummary();
 }

Why do I do that? Well because during TestDrivenDevelopment I like to run the tests all the time and there is nothing easier than pressing F5 on my keyboard.


You can download these samples: Part01: Assertions.xpo


That's it for today. In the next post I will try to explain exception handling (expected exceptions) and hopefully much more.

Comments

  • Anonymous
    September 19, 2006
    In this post I will try to describe exceptions handling using SysTest.
    Very often&amp;nbsp;applications...

  • Anonymous
    September 25, 2006
    In the first part I mentioned the following code: static void RunMySimpleTests(Args _args)
    {
       SysTestSuite...

  • Anonymous
    October 10, 2006
    We already know how to create test suites . Today I would like to cover some additional reasons for creating

  • Anonymous
    October 24, 2006
    In the series of previous posts I've covered TestClass es and TestSuite s. You should already know how

  • Anonymous
    March 11, 2007
    mmm.. nice design, I must say..

  • Anonymous
    March 14, 2007
    Du musst ein Fachmann sein - wirklich guter Aufstellungsort, den du hast!

  • Anonymous
    April 11, 2007
    Ich erklare meinen Freunden uber diese Seite. Interessieren!

  • Anonymous
    April 13, 2007
    Stupore! Amo questo luogo!:)))))))

  • Anonymous
    April 15, 2007
    E grande io ha trovato il vostro luogo! Le info importanti ottenute! ))