Is there a way to Create nunit Setup with arguments - c#

Is there a way to add arguments to an nunit setup method like this: public void SetUp(Point p = null) { /*code*/ }.
I tried it and got the following exception SetUp : System.Reflection.TargetParameterCountException : Parameter count mismatch

I think that your point is to avoid code duplication.
Try to extract base class with overriten method used in SetUp().
All derived class will execute tests from base class, with objects prepared in overriten OnSetUp()
[TestFixture]
public class BaseTestsClass
{
//some public/protected fields to be set in SetUp and OnSetUp
[SetUp]
public void SetUp()
{
//basic SetUp method
OnSetUp();
}
public virtual void OnSetUp()
{
}
[Test]
public void SomeTestCase()
{
//...
}
[Test]
public void SomeOtherTestCase()
{
//...
}
}
[TestFixture]
public class TestClassWithSpecificSetUp : BaseTestsClass
{
public virtual void OnSetUp()
{
//setup some fields
}
}
[TestFixture]
public class OtherTestClassWithSpecificSetUp : BaseTestsClass
{
public virtual void OnSetUp()
{
//setup some fields
}
}
Using parametrised TestFixture also can be usefull. Tests in class will be lunched per TestFixture, SetUp method also.
But remember that
Parameterized fixtures are (as you have discovered) limited by the fact that you can only use arguments that are permitted in attributes
Usage:
[TestFixture("some param", 123)]
[TestFixture("another param", 456)]
public class SomeTestsClass
{
private readonly string _firstParam;
private readonly int _secondParam;
public WhenNoFunctionCodeExpected(string firstParam, int secondParam)
{
_firstParam = firstParam;
_secondParam = secondParam;
}
[Test]
public void SomeTestCase()
{
...
}
}

Related

Casting to a base class using generics

I seem to have some trouble understanding generics in c#.
Basically i have a base class called ConfigWorker and a bunch of sub classes which should all use their own config class deriving from BaseConfig.
The ConfigWorker class i want to use should be determined dynamically during runtime given the name of the class as a parameter.
I can instantiate the sub class given it's name, but no matter what i try, i can't get the casting to a sensible base class to work.
Here's my code:
namespace DocumentHandler
{
public class BaseConfig
{
}
public class ConfigWorker<T> where T : BaseConfig
{
public virtual void Work(T options)
{
}
}
public class Worker1 : ConfigWorker<Worker1.Config>
{
public class Config : BaseConfig
{
public string test = "";
}
public override void Work(Config options)
{
//do something
}
}
public class Worker2 : ConfigWorker<Worker2.Config>
{
public class Config : BaseConfig
{
public string test = "";
}
public override void Work(Config options)
{
//do something else
}
}
public class Test
{
public static BaseConfig config;
public static void test()
{
(Activator
.CreateInstance(Type.GetType("DocumentHandler.Worker2"))
as ConfigWorker<BaseConfig>)
.Work(config);
}
}
}
The crucial line is
(Activator
.CreateInstance(Type.GetType("DocumentHandler.Worker2"))
as ConfigWorker<BaseConfig>)
.Work(config);
The casting to ConfigWorker<BaseConfig> returns null, as the cast can not be performed.
Trying to simply cast to ConfigWorker does not compile as the type parameter is missing.
Anything else i can try? CreateInstance obviously just returns an object and i need to cast that to be able to call the Work method
Any help is appreciated.
An instance of Worker2 is not a ConfigWorker<BaseConfig>! It's a ConfigWorker<Worker2.Config>. These are two totally different types. Generic classes are invariant. Only interfaces and delegates can be co- or contra-variant.
In your example, ConfigWorker is even contra-variant in T, meaning you use T as the type of an input parameter to a method. So what you try is actually dangerous.
Imagine your line would work: you get an variable of type ConfigWorker<BaseConfig>, so you could rely on this instance having a method Work() which takes a BaseConfig (or something derived from it) as argument. So nothing could stop you from calling it like
worker.Work(new Worker1.Config());
Compiles fine. But wait a moment! Didn't your line state that worker is a Worker2? Worker2 instances can only handle Worker2.Config arguments!
You completely loose type safety this way (well, you would if it was allowed).
There is a flaw in your class design.
This looks like a good problem that factory pattern has good good solution for.
Here is a simplified solution
namespace DocumentHandler
{
public interface IBaseConfig
{
}
public class ConfiManager : IBaseConfig
{
}
public abstract class WorkerFactory
{
private readonly IBaseConfig _config;
protected WorkerFactory(IBaseConfig config)
{
this._config = config;
}
public virtual void Work()
{
}
}
public class Worker1 : WorkerFactory
{
private readonly IBaseConfig _config;
public Worker1(IBaseConfig config):base(config)
{
_config = config;
}
public string test = "";
public override void Work()
{
//do something
}
}
public class Worker2 : WorkerFactory
{
private readonly IBaseConfig _config;
public string test = "";
public Worker2(IBaseConfig config):base(config)
{
this._config = config;
}
public override void Work()
{
Console.WriteLine("Hello world");
}
}
public class Test
{
public static IBaseConfig config = new ConfiManager();
public static void test()
{
WorkerFactory worker =
(Worker2) Activator.CreateInstance(Type.GetType("DocumentHandler.Worker2"), config);
worker.Work();
}
}
}

UnexpectedArgumentMatcherException when calling Setup second time

I have these two tests (stripped to the bare bones to replicate the error):
[TestFixture]
public class CreditorMapperTests
{
private IAbcContext _AbcContext;
[SetUp]
public void Setup()
{
_AbcContext = Substitute.For<IAbcContext>();
_AbcContext.CompanyInfo.Returns(x => new CompanyInfo(Arg.Any<Guid>()));
}
[Test]
public void A()
{
Creditor publishDocument = new Creditor();
publishDocument.CompanyExternalId = _AbcContext.CompanyInfo.UniqueId;
}
[Test]
public void B()
{
Creditor publishDocument = new Creditor();
publishDocument.CompanyExternalId = _AbcContext.CompanyInfo.UniqueId;
}
}
public interface IAbcContext
{
CompanyInfo CompanyInfo { get; }
}
public class CompanyInfo
{
public CompanyInfo(Guid uniqueId)
{
UniqueId = uniqueId;
}
public readonly Guid UniqueId;
}
public class Creditor
{
public Guid CompanyExternalId { get; set; }
}
The Setup() for A() runs fine. However when Setup() is called for B(), I get this error:
NSubstitute.Exceptions.UnexpectedArgumentMatcherException : Argument
matchers (Arg.Is, Arg.Any) should only be used in place of member
arguments. Do not use in a Returns() statement or anywhere else
outside of a member call. Correct use:
sub.MyMethod(Arg.Any()).Returns("hi") Incorrect use:
sub.MyMethod("hi").Returns(Arg.Any())
This only happens when I run both tests by running all tests in that class.
If I run B() by itself, the Exception is not thrown.
Why does Setup() for B() fail only when run automatically after A()?
(nb. both tests are identical).
I'm using NUnit v3.8.1 and NSubstitute v2.0.3

Prevent TestInitialize running for one TestMethod method

I have a set of unit tests that require TestInitialize to run for them to work... however, there is one specific test that i'd love to be able to run without running TestInitialize. Is there a way to do that?
It might look like this:
[TestClass]
public class BingBangBoom
{
[TestInitialize]
public void Setup()
{
// ...
}
[TestMethod]
public void Bing()
{
// ...
}
[TestMethod]
public void Bang()
{
// ...
}
[TestMethod(PreventInitialize)]
public void Boom
{
// ...
}
}
No worries if not, I can come up with an alternative solution
Edit - RE DavidG:
It seems a shame to have this:
[TestClass]
public class BingBangBoom
{
[TestInitialize]
public void Setup()
{
// ...
}
// 10 very related methods
}
[TestClass]
public class BingBangBoom2
{
// 1 method, even though it's entirely related to BingBangBoomin'
}
I guess it is what it is.
That's not immediately obvious, but surely doable.
Assuming you have attribute like this:
public class SkipInitializeAttribute : Attribute { }
The thing you need is public property inside your test class to be injected by testing framework:
public TestContext TestContext { get; set; }
And then just branch your initialization like this:
[TestInitialize]
public void Initialize()
{
bool skipInitialize = GetType().GetMethod(TestContext.TestName)
.GetCustomAttributes<SkipInitializeAttribute>().Any();
if (!skipInitialize)
{
// Initialization code here
}
}
Working sample as self-tested solution:
using System;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject1
{
public class SkipInitializeAttribute : Attribute
{
}
[TestClass]
public class UnitTest1
{
public TestContext TestContext { get; set; }
private bool IsInitializationDone { get; set; }
[TestInitialize]
public void Initialize()
{
bool skipInitialize = GetType().GetMethod(TestContext.TestName).GetCustomAttributes<SkipInitializeAttribute>().Any();
if (!skipInitialize)
{
// Initialization code here
IsInitializationDone = true;
}
}
[TestMethod]
public void TestMethod1()
{
Assert.IsTrue(IsInitializationDone);
}
[TestMethod]
[SkipInitialize]
public void TestMethod2()
{
Assert.IsFalse(IsInitializationDone);
}
[TestMethod]
public void TestMethod3()
{
Assert.IsTrue(IsInitializationDone);
}
}
}
And results:
Starting test execution, please wait...
Passed TestMethod1
Passed TestMethod2
Passed TestMethod3
Total tests: 3. Passed: 3. Failed: 0. Skipped: 0.
Test Run Successful.
Having this general idea in mind you can play with base class / helpers etc.

Can I customise a Fixture in an XUnit constructor for use with Theory and AutoData?

Here is what I am trying to do:
public class MyTests
{
private IFixture _fixture;
public MyTests()
{
_fixture = new Fixture();
_fixture.Customize<Thing>(x => x.With(y => y.UserId, 1));
}
[Theory, AutoData]
public void GetThingsByUserId_ShouldReturnThings(IEnumerable<Thing> things)
{
things.First().UserId.Should().Be(1);
}
}
I would expect the IEnumerable<Thing> things parameter passed into the test to each have a UserId of 1 but this is not what happens.
How can I make this so?
You can do that by creating a custom AutoData attribute derived-type:
internal class MyAutoDataAttribute : AutoDataAttribute
{
internal MyAutoDataAttribute()
: base(
new Fixture().Customize(
new CompositeCustomization(
new MyCustomization())))
{
}
private class MyCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Thing>(x => x.With(y => y.UserId, 1));
}
}
}
You may also add other Customizations. Just keep in mind that the order matters.
Then, change the test method to use MyAutoData attribute instead, as shown below:
public class MyTests
{
[Theory, MyAutoData]
public void GetThingsByUserId_ShouldReturnThings(IEnumerable<Thing> things)
{
things.First().UserId.Should().Be(1);
}
}

Find out the next test method to execute in MS TestInitialize

I keep the test data for specific test method in folder named the same as function. I previously had the same function call in each [TestMethod], ClearAllAndLoadTestMethodData() which determined the method name via StackTrace. Now, I moved this function to [TestInitialize]. How can I find the name of the method that is about to be executed?
I thought TestContext provide this. I have access to it via [AssemblyInitialize()] and on first run its property Name is set to name of the testmethod. However, later this doesn't change (if I save the object in static field).
The AssemblyInitialize method is executed only once before all your tests.
Use the TestContext inside the TestInitialize method:
[TestClass]
public class TestClass
{
[TestInitialize]
public void TestIntialize()
{
string testMethodName = TestContext.TestName;
}
[TestMethod]
public void TestMethod()
{
}
public TestContext TestContext { get; set; }
}
[TestClass]
public class MyTestClass
{
private static TestContext _testContext;
[ClassInitialize]
public static void TestFixtureSetup(TestContext context)
{
_testContext = context;
}
[TestInitialize]
public void TestIntialize()
{
string testMethodName = MyTestClass._testContext.TestName;
switch (testMethodName)
{
case "TestMethodA":
//todo..
break;
case "TestMethodB":
//todo..
break;
default:
break;
}
}
[TestMethod]
public void TestMethodA()
{
}
[TestMethod]
public void TestMethodB()
{
}
}

Categories