2 <Mono newbie coders start file>
5 For those who are new to Mono and are impatient to contribute
6 with code (uhh... you are brave!!) here is the document you
10 You will see all Mono hackers say the same (great minds have
11 similar way of thinking): First, DO WRITE TESTS!!!. In order
15 * Start with the NUnit Tests Guidelines. In the cvs
16 they are located at: mcs/class/doc/NUnitGuideli...
18 But wait, this is a document for impatient
19 people. So EVERYTHING should be here. Well, it is.
22 -------------------- cut here --------------------
24 Mono NUnit Test Guidelines and Best Practices
26 Authors: Nick Drochak <ndrochak@gol.com>
27 Martin Baulig <martin@gnome.org>
28 Last Update: 2002-03-02
33 This document captures all the good ideas people have had about
34 writing NUnit tests for the mono project. This document will be useful
35 for anyone who writes or maintains unit tests.
38 - mcs/class/README has an explanation of the build process and
39 how it relates to the tests.
40 - http://nunit.sourceforge.net is the place to find out about NUnit
44 If you are new to writing NUnit tests, there is a template you may use
45 to help get started. The file is:
47 mcs/class/doc/TemplateTest.cs
50 (2.- This is the point two!. This file is just after the end of the
51 guidelines. Copy/paste it in another buffer. And keep reading.)
54 Save a copy of this file in the appropriate test subdirecty (see
55 below), and replace all the [text] markers with appropriate
56 code. Comments in the template are there to guide you. You should also
57 look at existing tests to see how other people have written them.
58 mcs/class/corlib/Test/System.Collections/CollectionBaseTest.cs is a
59 small one that might help.
61 (3.- You reached the third point. And as expected, it's just here to
62 tell you that the content of CollectionBaseTest.cs is after the
63 TemplateTest.cs code at the end of these guidelines.)
65 The directory that will contain your new file depends on the
66 assembly/namespace of the class for which you are creating the
67 tests. Under mcs/class there is a directory for each assembly. In each
68 assembly there is a Test directory, e.g. mcs/class/corlib/Test. In the
69 Test directory there are sub-directories for each namespace in the
70 assembly, e.g. mcs/class/corlib/Test/Sytem. Put your new test file in
71 the appropriate sub-directory under Test for the class you are
74 Once your test class is complete, you need to add it to the
75 AllTests.cs file in the same directory as your new test. Add a call to
76 "suite.AddTest()" passing the name of your new test class's suite
77 property as the parameter. You will see examples in the AllTests.cs
78 file, so just copy and paste inside there.
80 Once all of that is done, you can do a 'make test' from the top mcs
81 directory. Your test class will be automagically included in the
82 build and the tests will be run along with all the others.
86 ** Provide an unique error message for Assert()
88 Include an unique message for each Assert() so that when the assert
89 fails, it is trivial to locate the failing one. Otherwise, it may be
90 difficult to determine which part of the test is failing. A good way
91 to ensure unique messages is to use something like #A01, #A02 etc.
95 AssertEquals("array match", compare[0], i1[0]);
96 AssertEquals("array match", compare[1], i1[1]);
97 AssertEquals("array match", compare[2], i1[2]);
98 AssertEquals("array match", compare[3], i1[3]);
102 AssertEquals("#A01", compare[0], i1[0]);
103 AssertEquals("#A02", compare[1], i1[1]);
104 AssertEquals("#A03", compare[2], i1[2]);
105 AssertEquals("#A04", compare[3], i1[3]);
107 Once you used such a number in an Assert(), don't change it later on -
108 people might use it it identify the test in bug reports or in mailing
111 ** Use AssertEquals() to compare things, not Assert().
113 Never compare two values with Assert() - if the test fails, people
114 have no idea what went wrong while AssertEquals() reports the failed
119 Assert ("A01", myTicks[0] == t1.Ticks);
123 AssertEquals ("A01", myTicks[0], t1.Ticks);
128 When writing your testcase, please make sure to provide a constructor
129 which takes no arguments:
132 public class DateTimeTest : TestCase
135 public DateTimeTest() : base ("[MonoTests.System.DateTimeTest]") {}
136 public DateTimeTest (string name): base(name) {}
138 public static ITest Suite
141 TestSuite suite = new TestSuite ();
150 Please keep the namespace within each test directory
151 consistent - all tests which are referenced in the same
152 AllTests.cs must be in the same namespace. Of course you can
153 use subnamespaces as you like - especially for subdirectories
156 For instance, if your AllTests.cs is in namespace "MonoTests"
157 and you have a subdirectory called "System", you can put all
158 the tests in that dir into namespace "MonoTests.System".
160 * Test your test with the microsoft runtime
162 If possible, try to run your testsuite with the Microsoft
163 runtime on Windows and make sure all tests in it pass. This is
164 especially important if you're writing a totally new testcase
165 - without this check you can never be sure that your testcase
166 contains no bugs ....
168 Don't worry if you're writing your test on Linux, other people
169 can test it for you on Windows.
171 Sometimes you may discover that a test doesn't show the
172 expected result when run with the Microsoft runtime - either
173 because there is a bug in their runtime or something is
174 misleading or wrong in their documentation. In this case,
175 please put a detailed description of the problem to
176 mcs/class/doc/API-notes and do also report it to the list -
177 we'll forward this to the Microsoft people from time to time
178 to help them fix their documentation and runtime.
180 -------------------- cut here ------------------------
183 -------------------- TemplateTest.cs begins ----------
185 // this is a template for making NUnit tests. Text enclosed in square
186 // brackets (and the brackets themselves) should be replaced by appropiate
189 // [File Name].cs - NUnit Test Cases for [explain here]
191 // [Author Name] ([Author email Address])
193 // (C) [Copyright holder]
196 // these are the standard namespaces you will need. You may need to add more
197 // depending on your tests.
198 using NUnit.Framework;
201 // all test namespaces start with "MonoTests." Append the Namespace that
202 // contains the class you are testing, e.g. MonoTests.System.Collections
203 namespace MonoTests.[Namespace]
206 // the class name should end with "Test" and start with the name of the class
207 // you are testing, e.g. CollectionBaseTest
208 public class [Class to be tested]Test : TestCase {
210 // there should be two constructors for your class. The first one
211 // (without parameters) should set the name to something unique.
212 // Of course the name of the method is the same as the name of the
214 public [Constructor]() : base ("[Namespace.Class]") {}
215 public [Constructor](string name) : base(name) {}
217 // this method is run before each Test* method is called. You can put
218 // variable initialization, etc. here that is common to each test.
219 // Just leave the method empty if you don't need to use it.
220 protected override void SetUp() {}
222 // this method is run after each Test* method is called. You can put
223 // clean-up code, etc. here. Whatever needs to be done after each test.
224 // Just leave the method empty if you don't need to use it.
225 protected override void TearDown() {}
227 // this property is required. You need change the parameter for
228 // typeof() below to be your class.
229 public static ITest Suite {
231 return new TestSuite(typeof([Classname here]));
235 // this is just one of probably many test methods in your test class.
236 // each test method must start with "Test". All methods in your class
237 // which start with "Test" will be automagically called by the NUnit
239 public void Test[Something] {
240 // inside here you will exercise your class and then call Assert()
244 ---------------------- TemplateTest.cs ends --------------
245 ---------------------- CollectionBaseTest.cs begins ------
247 // System.Collections.CollectionBase
248 // Test suite for System.Collections.CollectionBase
251 // Nick D. Drochak II
253 // (C) 2001 Nick D. Drochak II
258 using System.Collections;
259 using NUnit.Framework;
261 namespace MonoTests.System.Collections
264 public class CollectionBaseTest : TestCase
266 public CollectionBaseTest () : base ("System.Collection.CollectionBase testsuite") {}
267 public CollectionBaseTest (String name) : base (name) {}
269 // We need a concrete class to test the abstract base class
270 public class ConcreteCollection : CollectionBase
272 // These fields are used as markers to test the On* hooks.
273 public bool onClearFired;
274 public bool onClearCompleteFired;
276 public bool onInsertFired;
277 public int onInsertIndex;
278 public bool onInsertCompleteFired;
279 public int onInsertCompleteIndex;
281 public bool onRemoveFired;
282 public int onRemoveIndex;
283 public bool onRemoveCompleteFired;
284 public int onRemoveCompleteIndex;
286 public bool onSetFired;
287 public int onSetOldValue;
288 public int onSetNewValue;
289 public bool onSetCompleteFired;
290 public int onSetCompleteOldValue;
291 public int onSetCompleteNewValue;
293 // This constructor is used to test OnValid()
294 public ConcreteCollection()
301 // This constructor puts consecutive integers into the list
302 public ConcreteCollection(int i) {
307 for (j = 0; j< i; j++) {
312 // A helper method to look at a value in the list at a specific index
313 public int PeekAt(int index)
317 return (int) listObj[index];
320 // Mark the flag if this hook is fired
321 protected override void OnClear() {
322 this.onClearFired = true;
325 // Mark the flag if this hook is fired
326 protected override void OnClearComplete()
328 this.onClearCompleteFired = true;
331 // Mark the flag, and save the paramter if this hook is fired
332 protected override void OnInsert(int index, object value)
334 this.onInsertFired = true;
335 this.onInsertIndex = index;
338 // Mark the flag, and save the paramter if this hook is fired
339 protected override void OnInsertComplete(int index, object value)
341 this.onInsertCompleteFired = true;
342 this.onInsertCompleteIndex = index;
345 // Mark the flag, and save the paramter if this hook is fired
346 protected override void OnRemove(int index, object value)
348 this.onRemoveFired = true;
349 this.onRemoveIndex = index;
352 // Mark the flag, and save the paramter if this hook is fired
353 protected override void OnRemoveComplete(int index, object value)
355 this.onRemoveCompleteFired = true;
356 this.onRemoveCompleteIndex = index;
359 // Mark the flag, and save the paramters if this hook is fired
360 protected override void OnSet(int index, object oldValue, object newValue)
362 this.onSetFired = true;
363 this.onSetOldValue = (int) oldValue;
364 this.onSetNewValue = (int) newValue;
367 // Mark the flag, and save the paramters if this hook is fired
368 protected override void OnSetComplete(int index, object oldValue, object newValue)
370 this.onSetCompleteFired = true;
371 this.onSetCompleteOldValue = (int) oldValue;
372 this.onSetCompleteNewValue = (int) newValue;
374 } // public class ConcreteCollection
376 public static ITest Suite {
378 return new TestSuite (typeof(CollectionBaseTest));
382 // Check the count property
383 public void TestCount() {
384 ConcreteCollection myCollection;
385 myCollection = new ConcreteCollection(4);
386 Assert(4 == myCollection.Count);
389 // Make sure GetEnumerator returns an object
390 public void TestGetEnumerator() {
391 ConcreteCollection myCollection;
392 myCollection = new ConcreteCollection(4);
393 Assert(null != myCollection.GetEnumerator());
396 // OnValid disallows nulls
397 public void TestOnValid() {
398 ConcreteCollection myCollection;
400 myCollection = new ConcreteCollection();
402 catch (ArgumentNullException) {
406 // Test various Insert paths
407 public void TestInsert() {
408 ConcreteCollection myCollection;
411 // The constructor inserts
412 myCollection = new ConcreteCollection(numberOfItems);
413 Assert(myCollection.onInsertFired);
414 Assert(myCollection.onInsertCompleteFired);
416 // Using the IList interface, check inserts in the middle
417 IList listObj = myCollection;
418 listObj.Insert(1, 9);
419 Assert(myCollection.onInsertIndex == 1);
420 Assert(myCollection.onInsertCompleteIndex == 1);
421 Assert(myCollection.PeekAt(1) == 9);
424 // Test Clear and it's hooks
425 public void TestClear()
427 ConcreteCollection myCollection;
430 myCollection = new ConcreteCollection(numberOfItems);
431 myCollection.Clear();
432 Assert(myCollection.Count == 0);
433 Assert(myCollection.onClearFired);
434 Assert(myCollection.onClearCompleteFired);
437 // Test RemoveAt, other removes and the hooks
438 public void TestRemove()
440 ConcreteCollection myCollection;
443 // Set up a test collection
444 myCollection = new ConcreteCollection(numberOfItems);
446 // The list is 0-based. So if we remove the second one
447 myCollection.RemoveAt(1);
449 // We should see the original third one in it's place
450 Assert(myCollection.PeekAt(1) == 2);
451 Assert(myCollection.onRemoveFired);
452 Assert(myCollection.onRemoveIndex == 1);
453 Assert(myCollection.onRemoveCompleteFired);
454 Assert(myCollection.onRemoveCompleteIndex == 1);
455 IList listObj = myCollection;
457 // Confirm parameters are being passed to the hooks
458 Assert(myCollection.onRemoveIndex == 0);
459 Assert(myCollection.onRemoveCompleteIndex == 0);
462 // Test the random access feature
463 public void TestSet()
465 ConcreteCollection myCollection;
468 myCollection = new ConcreteCollection(numberOfItems);
469 IList listObj = myCollection;
471 Assert((int) listObj[0] == 99);
472 Assert(myCollection.onSetFired);
473 Assert(myCollection.onSetCompleteFired);
474 Assert(myCollection.onSetOldValue == 0);
475 Assert(myCollection.onSetCompleteOldValue == 0);
476 Assert(myCollection.onSetNewValue == 99);
477 Assert(myCollection.onSetCompleteNewValue == 99);
482 ----------------------- CollectionBaseTest.cs ends --------
485 * If you use Emacs, you might want to use the .emacs file and the
486 package developed by Brad Merrill mailto:zbrad@cybercom.net. It
487 will allow you to highlight and indent in C# style in your Emacs
488 editor. (XEmacs will still work but it'll also complain).
490 * CSharpDevelop is a GPLed IDE developed by IC#Code. Search for it
491 at sourceforge if you are interested in it.
493 * For those who Java: "A comparison of Microsoft's C# programming
494 language to Sun Microsystem's Java Programming language" by Dare
495 Obasanjo is a really good (very complete) text to read.
497 * Suggest this point and more, now I can't think of anything more.
502 (c) Jaime Anguiano Olarra.
504 The parts included in this document are property of their respective authors.