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
1.4 Testing string-value
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.
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.
To make things even shorter there is an ComTest operator =S=
that converts both side ToString()
before comparison.
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.
Again to make things shorter, there is operator =J=
that uses String.Join(", ", leftside)
to the left side of comparison.
In newer .net version it is also possible to compare arrays directly. That is best way if values are double-values.
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.
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.
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.
Same with .net8.0 and above:
If the array is not needed after test, it is possible to create array on the function call.
And with .net8.0 and above:
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.
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.
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.
One can think what are easier with .net8.0 and what are not:
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;
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.
In current .net one can test also 2D matrices directly.
Also one benefit is that decimal symbol has no harmful effect.
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.
The default tolerance is 6 digits and it can be changed by #TOLERANCE
:
In current .net it is also possible to test floating points directly. Default tolerance is 0.000001.
1.11 Expecting an exception
If some test SHOULD throw an exception, it can be written like:
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.
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:
divide the subroutine to function that formats the string to print and then print that string. Test the function:
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.
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 inTools/ComTest/Options
. Please check it and correct. - you have a virus scanner that prevents the run, see later below.
- your path to
- 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:
Do not use classname at all.
Change the name of namespace or the class.
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".
- one known problem is Comando Autosandbox.
- 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.