TestCaseSource and inheritance in NUnit 3

478 views
Skip to first unread message

Viktor Griph

unread,
Apr 26, 2016, 12:46:29 PM4/26/16
to NUnit-Discuss
Hi,

I'm currently working on migrating from NUnit 2.6.2 to NUnit 3.2.1 and run into a problem with TestCaseSoruce no longer accepting instance method. We have a case where several different tests uses the same test code, but different test case data in different fixtures. With 2.6.2 that was implemented by an abstract property referred to from the TestCaseSource. Obviously that is no longer possible in version 3 or later. Is there any suggested pattern that could be used to achieve similar behaviour in 3.x? Right now I'm planning on making the test implementation virtual, and override it in all sub classes specifying the Test and TestCaseSource attribute in each subclass and just call the base implementation for the test code. However it results in a lot of code duplication so I wanted to ask if there were any better way of doing it.

Regards
Viktor Griph

Charlie Poole

unread,
Apr 26, 2016, 1:15:43 PM4/26/16
to NUnit-Discuss
Can you post a code snippet to clarify what you mean?
> --
> You received this message because you are subscribed to the Google Groups
> "NUnit-Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to nunit-discus...@googlegroups.com.
> To post to this group, send email to nunit-...@googlegroups.com.
> Visit this group at https://groups.google.com/group/nunit-discuss.
> For more options, visit https://groups.google.com/d/optout.

Viktor Griph

unread,
Apr 27, 2016, 6:23:30 AM4/27/16
to NUnit-Discuss
One of the most simple usages of the pattern is something like this:

    [TestFixture]
    public abstract class EntlibConfigurationTestBase
    {
        private ConfigXmlDocument configFile;

        protected abstract IEnumerable<Category> Categories
        
        protected abstract string ConfigFile { get; }

        [OneTimeSetUp]
        public void TestFixtureSetup()
        {
            configFile = new ConfigXmlDocument();
            configFile.Load(ConfigFile);            
        }

        [Test]
        [TestCaseSource(nameof(Categories))]
        public void CategoryShallHaveCorrespondingSectionInEntlibConfig(Category category)
        {
            var categorySources = configFile.GetElementsByTagName("categorySources").Cast<XmlElement>().Single();
            var addNodes = categorySources.SelectNodes("add");
            Assert.IsNotNull(addNodes);
            var foundCategories =addNodes.Cast<XmlElement>().Select(x => x.GetAttribute("name")).ToHashSet();
            Assert.IsTrue(foundCategories.Contains(category.ToString()), "Category {0} must be defined as source in {1}", category, ConfigFile);
        }

        [Test]
        public void AllListenersMustBeDefined()
        {
            var listeners = configFile.SelectSingleNode("configuration/loggingConfiguration/listeners");
            Assert.IsNotNull(listeners);
            var addNodes = listeners.SelectNodes("add");
            Assert.IsNotNull(addNodes);
            var validListeners = addNodes.Cast<XmlElement>().Select(x => x.GetAttribute("name")).ToHashSet();
            addNodes = categorySources.SelectNodes("add/listeners/add");
            Assert.IsNotNull(addNodes);
            var usedLiseners = addNodes.Cast<XmlElement>().Select(x => x.GetAttribute("name")).ToHashSet();
            Assert.IsEmpty(usedLiseners.Except(validListeners).ToList());
        }
    }

    public class ServerLoggingTest : EntlibConfigurationTestBase
    {
        protected override IEnumerable<Category> Categories
        {
            get { ... } // logic to find which categories are actually used by the server code
        }

        protected override string ConfigFile
        {
            get { return "EntlibServer.config"; }
        }
    }

    public class ClientLoggingTest : EntlibConfigurationTestBase
    {
        protected override IEnumerable<Category> Categories
        {
            get { ... } // logic to find which categorie are actually used by the client code
        }

        protected override string ConfigFile
        {
            get { return "EntlibClient.config"; }
        }
    }

In this case working around it is to make test-method CategoryShallHaveCorrespondingSectionInEntlibConfig(Category category) virtual, and move the attributes to the subclasses, add an override and call the base implementation. That leads to code duplication in an undesirable, but at least manageable way. But I was wondering if there is a better solution that does not involve code duplication.

Charlie Poole

unread,
Apr 27, 2016, 11:59:35 AM4/27/16
to NUnit-Discuss
Hi Viktor,

I'm heading out on vacation. Someone else will continue to discuss
this with you.

Charlie

Viktor Griph

unread,
Apr 28, 2016, 3:46:18 AM4/28/16
to NUnit-Discuss
No worries. I'm not in an urgent need of an answer. I just wanted to know if there was a better take at solving this than what I've been doing.

Matthew

unread,
Nov 15, 2016, 6:37:18 PM11/15/16
to NUnit-Discuss
Hi Victor,

I'm currently migrating to Nunit 3 and have come across the same problem you face with overriding test cases.

I'm just wondering if you ever implemented a nicer solution that overriding the test signatures?

Cheers
Reply all
Reply to author
Forward
0 new messages