2 <Mono newbie coders start file>
3 <h1> A little help for mono newbie coders </h1>
6 For those who are new to Mono and are impatient to contribute
7 with code (uhh... you are brave!!) here is the document you
11 You will see all Mono hackers say the same (great minds have
12 similar way of thinking): First, DO WRITE TESTS!!!. In order
16 * Start with the NUnit Tests Guidelines. In the cvs
17 they are located at: mcs/class/doc/NUnitGuideli...
19 * But wait, this is a document for impatient
20 people. So EVERYTHING should be here. Well, it is.
24 <h2> The NUnit Tests Guidelines document </h2>
26 Mono NUnit Test Guidelines and Best Practices
28 Authors: Nick Drochak <ndrochak@gol.com>
29 Martin Baulig <martin@gnome.org>
30 Last Update: 2002-03-02
35 This document captures all the good ideas people have had
36 about writing NUnit tests for the mono project. This document
37 will be useful for anyone who writes or maintains unit tests.
39 <b> Other resources </b>
41 - mcs/class/README has an explanation of the build process and
42 how it relates to the tests.
43 - http://nunit.sourceforge.net is the place to find out about
46 <b> Getting Started </b>
48 If you are new to writing NUnit tests, there is a template
49 you may use to help get started. The file is:
51 mcs/class/doc/TemplateTest.cs
54 (2.- This is the point two!. This file is just after the end
55 of the guidelines. Copy/paste it in another buffer. And keep
58 Save a copy of this file in the appropriate test subdirecty
59 (see below), and replace all the [text] markers with
60 appropriate code. Comments in the template are there to guide
61 you. You should also look at existing tests to see how other
62 people have written them.
64 mcs/class/corlib/Test/System.Collections/CollectionBaseTest.cs
66 is a small one that might help.
68 (3.- You reached the third point. And as expected, it's just
69 here to tell you that the content of CollectionBaseTest.cs is
70 after the TemplateTest.cs code at the end of these
73 The directory that will contain your new file depends on the
74 assembly/namespace of the class for which you are creating the
75 tests. Under mcs/class there is a directory for each assembly.
76 In each assembly there is a Test directory, e.g.
77 mcs/class/corlib/Test. In the Test directory there are
78 sub-directories for each namespace in the assembly, e.g.
79 mcs/class/corlib/Test/Sytem. Put your new test file in the
80 appropriate sub-directory under Test for the class you are
83 Once your test class is complete, you need to add it to the
84 AllTests.cs file in the same directory as your new test. Add a
85 call to "suite.AddTest()" passing the name of your new test
86 class's suite property as the parameter. You will see examples
87 in the AllTests.cs file, so just copy and paste inside there.
89 Once all of that is done, you can do a 'make test' from the top
90 mcs directory. Your test class will be automagically included
91 in the build and the tests will be run along with all the
96 <b> Provide an unique error message for Assert() </b>
98 Include an unique message for each Assert() so that when the
99 assert fails, it is trivial to locate the failing one.
100 Otherwise, it may be difficult to determine which part of the
101 test is failing. A good way to ensure unique messages is to use
102 something like #A01, #A02 etc.
106 AssertEquals("array match", compare[0], i1[0]);
107 AssertEquals("array match", compare[1], i1[1]);
108 AssertEquals("array match", compare[2], i1[2]);
109 AssertEquals("array match", compare[3], i1[3]);
113 AssertEquals("#A01", compare[0], i1[0]);
114 AssertEquals("#A02", compare[1], i1[1]);
115 AssertEquals("#A03", compare[2], i1[2]);
116 AssertEquals("#A04", compare[3], i1[3]);
118 Once you used such a number in an Assert(), don't change it
119 later on - people might use it it identify the test in bug
120 reports or in mailing lists.
122 <b> Use AssertEquals() to compare things, not Assert(). </b>
124 Never compare two values with Assert() - if the test fails,
125 people have no idea what went wrong while AssertEquals()
126 reports the failed value.
130 Assert ("A01", myTicks[0] == t1.Ticks);
134 AssertEquals ("A01", myTicks[0], t1.Ticks);
137 <b> Constructors </b>
139 When writing your testcase, please make sure to provide a
140 constructor which takes no arguments:
143 public class DateTimeTest : TestCase
146 public DateTimeTest() : base ("[MonoTests.System.DateTimeTest]") {}
147 public DateTimeTest (string name): base(name) {}
149 public static ITest Suite
152 TestSuite suite = new TestSuite ();
161 Please keep the namespace within each test directory
162 consistent - all tests which are referenced in the same
163 AllTests.cs must be in the same namespace. Of course you can
164 use subnamespaces as you like - especially for subdirectories
167 For instance, if your AllTests.cs is in namespace "MonoTests"
168 and you have a subdirectory called "System", you can put all
169 the tests in that dir into namespace "MonoTests.System".
171 <b> Test your test with the microsoft runtime </b>
173 If possible, try to run your testsuite with the Microsoft
174 runtime on Windows and make sure all tests in it pass. This is
175 especially important if you're writing a totally new testcase
176 - without this check you can never be sure that your testcase
177 contains no bugs ....
179 Don't worry if you're writing your test on Linux, other people
180 can test it for you on Windows.
182 Sometimes you may discover that a test doesn't show the
183 expected result when run with the Microsoft runtime - either
184 because there is a bug in their runtime or something is
185 misleading or wrong in their documentation. In this case,
186 please put a detailed description of the problem to
187 mcs/class/doc/API-notes and do also report it to the list -
188 we'll forward this to the Microsoft people from time to time
189 to help them fix their documentation and runtime.
192 -------------------- TemplateTest.cs begins ----------
194 // this is a template for making NUnit tests. Text enclosed
195 // in square brackets (and the brackets themselves) should be
196 // replaced by appropiate code.
198 // [File Name].cs - NUnit Test Cases for [explain here]
200 // [Author Name] ([Author email Address])
202 // (C) [Copyright holder]
205 // these are the standard namespaces you will need. You may
206 // need to add more depending on your tests.
207 using NUnit.Framework;
210 // all test namespaces start with "MonoTests." Append the
211 // Namespace that contains the class you are testing, e.g.
212 // MonoTests.System.Collections
213 namespace MonoTests.[Namespace]
216 // the class name should end with "Test" and start with the name
217 // of the class you are testing, e.g. CollectionBaseTest
218 public class [Class to be tested]Test : TestCase {
220 // there should be two constructors for your class. The first
221 // one (without parameters) should set the name to something
223 // Of course the name of the method is the same as the name of
225 public [Constructor]() : base ("[Namespace.Class]") {}
226 public [Constructor](string name) : base(name) {}
228 // this method is run before each Test* method is called. You
229 // can put variable initialization, etc. here that is common to
231 // Just leave the method empty if you don't need to use it.
232 protected override void SetUp() {}
234 // this method is run after each Test* method is called. You
235 // can put clean-up code, etc. here. Whatever needs to be done
236 // after each test. Just leave the method empty if you don't need
238 protected override void TearDown() {}
240 // this property is required. You need change the parameter for
241 // typeof() below to be your class.
242 public static ITest Suite {
244 return new TestSuite(typeof([Classname here]));
248 // this is just one of probably many test methods in your test
249 // class. each test method must start with "Test". All methods
250 // in your class which start with "Test" will be automagically
251 // called by the NUnit framework.
252 public void Test[Something] {
253 // inside here you will exercise your class and then
258 ---------------------- TemplateTest.cs ends --------------
260 ---------------------- CollectionBaseTest.cs begins ------
262 // System.Collections.CollectionBase
263 // Test suite for System.Collections.CollectionBase
266 // Nick D. Drochak II
268 // (C) 2001 Nick D. Drochak II
273 using System.Collections;
274 using NUnit.Framework;
276 namespace MonoTests.System.Collections
279 public class CollectionBaseTest : TestCase
281 public CollectionBaseTest () : base
282 ("System.Collection.CollectionBase testsuite")
284 public CollectionBaseTest (String name) : base (name)
287 // We need a concrete class to test the abstract base
289 public class ConcreteCollection : CollectionBase
291 // These fields are used as markers to test
293 public bool onClearFired;
294 public bool onClearCompleteFired;
296 public bool onInsertFired;
297 public int onInsertIndex;
298 public bool onInsertCompleteFired;
299 public int onInsertCompleteIndex;
301 public bool onRemoveFired;
302 public int onRemoveIndex;
303 public bool onRemoveCompleteFired;
304 public int onRemoveCompleteIndex;
306 public bool onSetFired;
307 public int onSetOldValue;
308 public int onSetNewValue;
309 public bool onSetCompleteFired;
310 public int onSetCompleteOldValue;
311 public int onSetCompleteNewValue;
313 // This constructor is used to test OnValid()
314 public ConcreteCollection()
321 // This constructor puts consecutive integers into the list
322 public ConcreteCollection(int i) {
327 for (j = 0; j< i; j++) {
332 // A helper method to look at a value in the
333 // list at a specific index
334 public int PeekAt(int index)
338 return (int) listObj[index];
341 // Mark the flag if this hook is fired
342 protected override void OnClear() {
343 this.onClearFired = true;
346 // Mark the flag if this hook is fired
347 protected override void OnClearComplete()
349 this.onClearCompleteFired = true;
352 // Mark the flag, and save the paramter if
353 // this hook is fired
354 protected override void OnInsert(int index,
357 this.onInsertFired = true;
358 this.onInsertIndex = index;
361 // Mark the flag, and save the paramter if
362 // this hook is fired
363 protected override void OnInsertComplete(int index,
366 this.onInsertCompleteFired = true;
367 this.onInsertCompleteIndex = index;
370 // Mark the flag, and save the paramter if this hook
372 protected override void OnRemove(int index,
375 this.onRemoveFired = true;
376 this.onRemoveIndex = index;
379 // Mark the flag, and save the paramter if this hook
381 protected override void OnRemoveComplete(int index,
384 this.onRemoveCompleteFired = true;
385 this.onRemoveCompleteIndex = index;
388 // Mark the flag, and save the paramters if this hook
390 protected override void OnSet(int index, object oldValue,
393 this.onSetFired = true;
394 this.onSetOldValue = (int) oldValue;
395 this.onSetNewValue = (int) newValue;
398 // Mark the flag, and save the paramters if this hook
400 protected override void OnSetComplete(int index,
404 this.onSetCompleteFired = true;
405 this.onSetCompleteOldValue = (int) oldValue;
406 this.onSetCompleteNewValue = (int) newValue;
408 } // public class ConcreteCollection
410 public static ITest Suite {
413 (typeof(CollectionBaseTest));
417 // Check the count property
418 public void TestCount() {
419 ConcreteCollection myCollection;
420 myCollection = new ConcreteCollection(4);
421 Assert(4 == myCollection.Count);
424 // Make sure GetEnumerator returns an object
425 public void TestGetEnumerator() {
426 ConcreteCollection myCollection;
427 myCollection = new ConcreteCollection(4);
428 Assert(null != myCollection.GetEnumerator());
431 // OnValid disallows nulls
432 public void TestOnValid() {
433 ConcreteCollection myCollection;
435 myCollection = new ConcreteCollection();
437 catch (ArgumentNullException) {
441 // Test various Insert paths
442 public void TestInsert() {
443 ConcreteCollection myCollection;
446 // The constructor inserts
447 myCollection = new ConcreteCollection(numberOfItems);
448 Assert(myCollection.onInsertFired);
449 Assert(myCollection.onInsertCompleteFired);
451 // Using the IList interface, check inserts in the middle
452 IList listObj = myCollection;
453 listObj.Insert(1, 9);
454 Assert(myCollection.onInsertIndex == 1);
455 Assert(myCollection.onInsertCompleteIndex == 1);
456 Assert(myCollection.PeekAt(1) == 9);
459 // Test Clear and it's hooks
460 public void TestClear()
462 ConcreteCollection myCollection;
465 myCollection = new ConcreteCollection(numberOfItems);
466 myCollection.Clear();
467 Assert(myCollection.Count == 0);
468 Assert(myCollection.onClearFired);
469 Assert(myCollection.onClearCompleteFired);
472 // Test RemoveAt, other removes and the hooks
473 public void TestRemove()
475 ConcreteCollection myCollection;
478 // Set up a test collection
479 myCollection = new ConcreteCollection(numberOfItems);
481 // The list is 0-based. So if we remove the second one
482 myCollection.RemoveAt(1);
484 // We should see the original third one in it's place
485 Assert(myCollection.PeekAt(1) == 2);
486 Assert(myCollection.onRemoveFired);
487 Assert(myCollection.onRemoveIndex == 1);
488 Assert(myCollection.onRemoveCompleteFired);
489 Assert(myCollection.onRemoveCompleteIndex == 1);
490 IList listObj = myCollection;
492 // Confirm parameters are being passed to the hooks
493 Assert(myCollection.onRemoveIndex == 0);
494 Assert(myCollection.onRemoveCompleteIndex == 0);
497 // Test the random access feature
498 public void TestSet()
500 ConcreteCollection myCollection;
503 myCollection = new ConcreteCollection(numberOfItems);
504 IList listObj = myCollection;
506 Assert((int) listObj[0] == 99);
507 Assert(myCollection.onSetFired);
508 Assert(myCollection.onSetCompleteFired);
509 Assert(myCollection.onSetOldValue == 0);
510 Assert(myCollection.onSetCompleteOldValue == 0);
511 Assert(myCollection.onSetNewValue == 99);
512 Assert(myCollection.onSetCompleteNewValue == 99);
517 ----------------------- CollectionBaseTest.cs ends --------
521 * If you use Emacs, you might want to use the .emacs
522 file and the package developed by Brad Merrill
523 mailto:zbrad@cybercom.net. It will allow you to
524 highlight and indent in C# style in your Emacs
525 editor. (XEmacs will still work but it'll also
528 * CSharpDevelop is a GPLed IDE developed by IC#Code.
529 Search for it at sourceforge if you are interested
532 * For those who Java: "A comparison of Microsoft's
533 C# programming language to Sun Microsystem's Java
534 Programming language" by Dare Obasanjo is a really good
535 (very complete) text to read.
537 * Suggest this point and more, now I can't think of
543 (c) 2002, <a href="mailto:jaime@geneura.ugr.es">Jaime Anguiano Olarra</a>.
545 The parts included in this document are property of their
548 Note: The identation of the source code has been changed a bit
549 so it could fit better in the website. Anyway, as nothing more
550 changed, the files should work as expected.