# exampleTest

1. ComTest C# -examples

ComTest is a small helper language to make writing NUnit tests easier. The tests are written to program comment using ComTest macro language and then those comments are translated to NUnit tests.

On examples below one can run tests and look what kind of NUnit tests are generated.

ComTest comment block should include:

    /// <example>
    /// <pre name="test">
    ///    ... mix of ComTest language and normal C#
    /// </pre>
    /// </example>

1.1 Testing functions with Input/Output

Functions that uses for example ReadLine or WriteLine are not easy to test. It is possible with help of some helper objects that capture input and/or ouput, but they are out of the scope of this course. So those functions we do not test in this course.

1.2 ComTest test operators

1.3 Function that returns an int

# Matrix
# shellint

1.4 Testing string-value

# HalfOfString

1.5 Testing StringBuilder-value

Because StringBuilder is not a string, it must be converted to a string before testing.

When utilizing a void subroutine that modifies its parameters passed by reference, it is necessary to call the subroutine first and after that inspect the altered state of the parameters.

# HalfOfStringBuilder0

In the manner described above, each test will consist of at least 3 lines. Even those 3 lines could be writen to one line, when writing code in a TDD mindset, consideration is given to making the code as easy to test and read as possible. In this case, it is advisable to change the void subroutine to the function returning the most significant thing for testing purposes. In the previous example, it was the reference to StringBuilder. Consequently, each test can ultimately be condensed to one line.

# HalfOfStringBuilder1

To make things even shorter there is an ComTest operator =S= that converts both side ToString() before comparison.

# HalfOfStringBuilder2
# shellsb2

1.6 Testing 1-dim array

When testing the whole contents of 1-dim array, the old way is to change it to a string using Join-function.

# Numbers1

Again to make things shorter, there is operator =J= that uses String.Join(", ", leftside) to the left side of comparison.

# Numbers2
# shellnumbers2

In newer .net version it is also possible to compare arrays directly. That is best way if values are double-values.

# onedimarray1n

With .NET 8.0 and above, it is also possible to use collection elements with []. The problem is that without a type cast, it is not recognized as a standard array on the right side of the comparison.

# onedimarray1nb

If function changes values in array, one must first call function and then test the changed array. Many times this can be done by joining the array to string.

# ChangeWordsArray1

Previous is quite long way to test and in TDD spirit it might be good idea to do function that returns a reference to changed array. And then creating the array to test in function call, every test case can be implemented in one row.

# ChangeWordsArray2
# shellChangeWordsArray2

Same with .net8.0 and above:

# ChangeWordsArray2b

If the array is not needed after test, it is possible to create array on the function call.

# ArraySum

And with .net8.0 and above:

# ArraySumb
# testinglists

1.7 Testing lists

Lists can be tested almost same way than 1-dim arrays. So lists can be tested be converting them to string by String.Join. Nowadays better method is test lists directly. In number lista, especially double lists, that prevents problems with decimal symbols.

# ListOfNumbers

If function changes values in list, one must first call function and then test the changed list. Many times this can be done by joining the array to string.

# ChangeWordsList1

Previous is quite long way to test and in TDD spirit it might be good idea to do function that returns a reference to changed list. And then creating the list to test in function call, every test case can be implemented in one row.

# ChangeWordsList2
# shellChangeWordsList2

One can think what are easier with .net8.0 and what are not:

# ChangeWordsList2b

1.8 Be careful with double values converted to string

In different cultures the decimal symbol is different. For example in Finland it is comma (,) and in USA it is period (.).

To prevent problems with converting double values to strings, it might be best to change the culture to some fixed culture before test code by inserting code like:

/// System.Globalization.CultureInfo.CurrentCulture = new System.Globalization.CultureInfo("en-US");

Note that this requires at least 4.6 version of .Net framework.

With older .Net version the safest is:

/// var ci = new System.Globalization.CultureInfo("fi-FI");
/// ci.NumberFormat.NumberDecimalSeparator = ".";
/// System.Threading.Thread.CurrentThread.CurrentCulture = ci;
# matrix

1.9 Testing 2-dim array

One way to test 2-dim arrays (matrix) is to test few important values like:

mat[0,0] ~~~ 0.1;
mat[1,1] ~~~ 0.7;

Another old way to test is to convert the matrix to a string using:

String.Join(" ",mat.Cast<double>()) === "0.1 0.3 0.5 0.7";

The problem with that is that if we have two matrices with the same values, but in different number of rows and columns, we may get wrong result.

# Matrices1

In current .net one can test also 2D matrices directly.
Also one benefit is that decimal symbol has no harmful effect.

# Matrices2

Implementation of Jonoksi-function

1.10 Testing floating point numbers

Because of the internal representation of the floating point numbers, they can not be compared with an "equal" sign, but compare whether they fall within a certain "tolerance", a margin.

# DoubleAlmost

The default tolerance is 6 digits and it can be changed by #TOLERANCE:

# DoubleTolerance

In current .net it is also possible to test floating points directly. Default tolerance is 0.000001.

# DoubleEqTolerance
# THROWS

1.11 Expecting an exception

If some test SHOULD throw an exception, it can be written like:

# ExpectException

and then if it DOES NOT throw an excption, it is test error. The value (in this case a) does not matter, because the exception comes before the value is used. So in this kind of tests the value can be arbitrary. The exception name should be checked from API-documents, or it could be own exception class if user have done that and throws it in test case.

# shellExpectException
# testprint

1.12 Testings subroutines that print something

It is not easy to test a subroutine that prints something. But those subroutines can be designed so that testing comes easier. Instead of:

# print1

divide the subroutine to function that formats the string to print and then print that string. Test the function:

# print2

1.13 Test using table format

Sometimes complicated tests may be hard to write and even harder to read what should be result by what parameters. This can be simplified by ComTest Table format. The idea is to write one template test and mark test and result parameters by names starting by $-sign. Then one writes table where parameters are in columns. A textual replacement is made to change the template test to real test.

Below is examples from previous examples by using table format. Note that in table's header line column separator | must be separated by at least one space from column name. And at least one empty line should separate test template from test table.

# MatrixTbl
# shellMatrixTbl
# HalfOfStringTbl
# shellHalfOfStringTbl
# HalfOfStringBuilderTbl
# shellHalfOfStringBuilderTbl
# ListOfNumbersTbl
# shellListOfNumbersTbl
# Matrices2Tbl
# shellMatrices2Tbl
# Time
# shellTimeTbl

2. Problems

2.1 VS solution verkkolevyllä

Jos solution sijaitsee verkkolevyllä, ei Comtest toimi, koska VS ei luota verkkolevyihin eikä siksi suostu lataamaan Comtestin solutioniin tekemiä tiedostoja.

Tilanteen voi korjata avaamalla

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE 

kansiossa (tai minne ikinä asensitkaan VS:n) olevan devenv.exe.config -tiedoston ja lisäämällä siihen yhden rivin. Mutta jotta kaikki olisi mahdollisimman vaikeaa, on ko. tiedostoon kirjoittaminen estetty (tai ainakin minulla oli), joten joudut avaamaan suosikki tekstieditorisi administratorina (hiiren kakkosnappi -> Run as Administrator) että voit muokata tuota tiedostoa. Tuohon tiedostoon pitää lisätä rivi

<loadFromRemoteSources enabled="true" /> 

heti rivin

<runtime>

perään. Tallenna tiedosto ja käynnistä VS varmuuden vuoksi uudelleen, ja ComTestin pitäisi nyt toimia.

2.2 Known problems

  • does not work with Visual Studio Express (contains no test framework)
  • may not work on mounted or substed drives (sometimes works???).
    The project must be in real local physical disk drive.
  • if you get an error saying something like No output from ComTest, there are two options:
    • your path to ComTest.jar is not correct in Tools/ComTest/Options. Please check it and correct.
    • you have a virus scanner that prevents the run, see later below.
  • if you get an error that says something like: ComTest: File not found, then your Java is not found. Either you have not installed the Java or it is not in the path. In first case install Java, in second case add the full path for Java:
    • go to command line and write:

       dir c:\java.exe /s

      you should get something like:

        Directory of c:\Program Files (x86)\Java\jre7\bin
      
        12.06.2013  21:43           175 016 java.exe
                   1 File(s)        175 016 bytes
    • in this example case (the path can be something else also), go to your Visual Studion and open Tools/ComTest/Options and write to Java-path: (note also the "):

       "c:\Program Files (x86)\Java\jre7\bin\java.exe"
  • if you use namespace and your namespace have same name than your class, then you may have problems when using classname. Like:

     public namespace Matrix
     {
       public class Matrix
       {
      ...
      /// Matrix.WhatRowContains(m, 12) === 3;

    Solution:

    1. Do not use classname at all.

    2. Change the name of namespace or the class.

    3. Write the the test line using both namespace and classname:

      /// Matrix.Matrix.WhatRowContains(m, 12) === 3;
  • classes, methods and possible namespaces must be public.
  • if you load new Plugin, load the new ComTest.jar at the same time.
  • sometimes when run tests in Solution that Contains Jypeli (XNA), says that "Specified cast is not valid" or "No such interface supported...". Then it helps to delete all generated Test-projects that include Jypeli (XNA).
  • some virus scanners may prevent the run for Java or ComTest. The result is a screen where its says: "No output from ComTest".
  • the snippet installer does not work if you have the Windows Phone SDK installed. This is not something we can fix, unfortunately. See: MSDN forum post
  • if you get error like:

      C:\Users\documents\visual (Unknown) || skipped: file not found
      studion (Unknown) || skipped: file not found
      ...

    then your project (or solution) is under path where is spaces in pathname. Please move to directory where is no spaces in the name.

  • if you get error like:

      Picked up _JAVA_OPTIONS: -Djava.vendor="Sun Microsystems Inc."
      Error occurred during initialization of VM
      java/lang/NoClassDefFoundError: java/lang/Object

    then at least one case the java was somehow damaged. Changed to use other java.exe in other directory helped. You may try to go to command line and look what its says ig you run exactly same Java like:

      "C:\Program Files (x86)\Java\jre7\bin\java.exe" -version

    if you still get the error, the Java is damaged.

These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.