Prevent users from overriding test framework setup/teardown functionality #1087
Labels
awaits:discussion
design
is:enhancement
New feature or request
is:task
A chore to be done
pri:normal
testability
Milestone
Is there an existing issue for this?
Task description
In Lucene, it was not possible to override the
BeforeClass
,AfterClass
,, orBefore
methods. This was enforced by the compiler by declaring the methods static.After
In Lucene.NET, we have defined these methods as virtual instance methods. This because NUnit calls the methods that implement the
[SetUp]
,[OneTimeSetUp]
,[TearDown]
and[OneTimeTearDown]
attributes in the reverse order with respect to inheritance as JUnit and it was the quickest way to fix the calling order issue (and in turn, we were able to debug the tests sooner). ForOneTimeSetUp()
, theLuceneTestCase
base class needs to be called first, so this approach allows the most derived class to call the root base class by usingbase.OneTimeSetUp()
and cascading it through each level of inheritance.While this works for our internal purposes, it allows users to override the methods and not call the base class. This can disable critical functionality for setting up or tearing down the test framework, which ideally the user would not be able to do.
I have analyzed NUnit thoroughly (in the past). Since these methods are called during the execution phase of the test run (which NUnit gives us no control over), there is no way to change the order. At least not without creating our own fork of NUnit. However, I thought of a way we might be able to fix this post-NUnit.
SetUp()
,OneTimeSetUp()
,andTearDown()
OneTimeTearDown()
as static as they were in Lucene using the original NUnit[SetUp]
,[OneTimeSetUp]
,and[TearDown]
[OneTimeTearDown]
attributes. These should be renamed beginning with a double underscore and be given theEditorBrowsable(EditorBrowsableState.Never)]
attribute.[SetUp]
,[OneTimeSetUp]
,[TearDown]
and[OneTimeTearDown]
attributes that are nested inside of theLuceneTestCase
class for users. These attributes will be owned by our test framework and unknown to NUnit. We can add anOrder
property that can optionally be set to define which order to execute them in when 2 or more are defined in the same class. This allows users to use attributes with names they are familiar with and as long as they don't fully qualify them, they will be our attributes rather than NUnit's. We use this approach already on[TestFixtureAttribute]
.[BeforeSetUp]
,[BeforeOneTimeSetUp]
,[AfterTearDown]
and[AfterOneTimeTearDown]
attributes that give the user the option to execute code prior to setup and after teardown. Note that using custom attributes based off of NUnit interfaces may be an alternative to this (basically, if you need to run something beforeSetUp()
orOneTimeSetUp()
or afterTearDown()
orOneTimeTearDown()
, create an attribute to do it and decorate either the class or the test, as appropriate).SetUp()
,OneTimeSetUp()
,TearDown()
andOneTimeTearDown()
methods inLuceneTestCase
, find the attributes for the current class and all classes that it inherits, order them appropriately, and execute them.Pros
tests:slow
property is set tofalse
#739. It will be straightforward to conditionally stop the call to the actual setup and tear down methods based on a custom attribute if we are calling these methods instead of NUnit.Cons
Note that we should analyze how the Reflection calls are done in NUnit so we can optimize. It might make sense to piggyback off of the test discovery phase (
[TestFixtureAttribute]
) to store the metadata about where the attributes are located and even the appropriate order to call them in, which can be stored in theRandomizedContext
class instance (which only applies to the currently running test).After it is implemented, we should also revert the existing
SetUp()
,OneTimeSetUp()
,andTearDown()
OneTimeTearDown()
methods of subclasses to the way they were in Lucene. Most of them were static, and several of them had names other than these (although, we should stick with these naming conventions instead of the before/after conventions that were used in Java - see #1016).The text was updated successfully, but these errors were encountered: