Getting info from currently running unit test - c#

I have to find info about the currently running UnitTest from a helper class' static method.
The Idea is getting a unique key from each test.
I thought about using TestContext, not sure if it is possible.
Exemple
[TestClass]
public void MyTestClass
{
public TestContext TestContext { get; set; }
[TestMethod]
public void MyTestMethod()
{
TestContext.Properties.Add("MyKey", Guid.NewGuid());
//Continue....
}
}
public static class Foo
{
public static Something GetSomething()
{
//Get the guid from test context.
//Return something base on this key
}
}
We are currently storing this key on the thread with Thread.SetData, but it is problematic if the tested code spawn multiple thread. For each thread I need to get the same key for a given unit test.
Foo.GetSomething() is not called from the unittest itself. The code calling it is a mock injected by Unity.
Edit
I'll explain the context a little bit, because it seems to be confusing.
The object created via unity is entity framework's context. When running unit tests, the context get its data in a structure that is created by Foo.GetSomething. Let's call it DataPersistance.
DataPersistance cannot be a singleton, because unit tests would impact each others.
We currently have one instance of DataPersistance per thread, witch is nice as long as the tested code is single threaded.
I want one instance of DataPersistance per unit test. If a could get an unique guid per test, I could resolve the instance for this test.

public static class Foo
{
public static Something GetSomething(Guid guid)
{
//Return something base on this key
return new Something();
}
}
Test:
[TestClass]
public void MyTestClass
{
public TestContext TestContext { get; set; }
[TestMethod]
public void MyTestMethod()
{
Guid guid = ...;
Something something = Foo.GetSomething(guid);
}
}

Related

Is there a way to mimic the function of startup.cs in unit test cases while running multiple tests together? [duplicate]

This question already has answers here:
xUnit.net: Global setup + teardown?
(6 answers)
Closed 2 years ago.
I am trying to test some code that uses a static class. The static class has a initialization method which can be called only once and throws exception if called second time. I have multiple test cases which tests the code that need to access the static class. In the code the initialization is done in startup.cs. How do I do something similar for test cases. I am using x-unit for unit testing.
public static class UniqueId
{
public static void Initialize()
{
if (_generator != null)
throw new Exception("Already initialized.");
_generator = new IdGenerator();
}
private static IdGenerator _generator = null;
public static BigId NextId()
{
if (_generator == null)
throw new Exception("Not initialized.");
return _generator.NextId();
}
}
Code that I want to test:
public string GenerateId
{
return UniqueId.NextId().ToString()
}
In your specific case, you need to set your class to implement the IDisposible and just call Dispose() when you want to destroy it.
Here a example:
namespace Prime.UnitTests.Services
{
[TestFixture]
public class YourClassTest
{
[SetUp]
public void SetUp()
{
//some configs...
}
[Test]
public void Test_size_String_1()
{
UniqueId.Initialize();
Assert.IsFalse(UniqueId.NextId().ToString() == 10); // quick example...
UniqueId.Dispose();
}
[Test]
public void Test_size_String_2XPTO()
{
UniqueId.Initialize();
Assert.IsFalse(UniqueId.NextId().ToString() == 115); // quick example...
UniqueId.Dispose();
}
}
}
public static class UniqueId : IDisposable
{
public static void Initialize()
{
if (_generator != null)
throw new Exception("Already initialized.");
_generator = new IdGenerator();
}
private static IdGenerator _generator = null;
public static BigId NextId()
{
if (_generator == null)
throw new Exception("Not initialized.");
return c.NextId();
}
public void Dispose()
{
_generator?.Dispose(); //Depends of the context of your IdGenerator
//or
_generator == null;
}
}
Assuming I understood, in MSTest, look into [TestInitialize], [ClassInitialize] (likely what you need) and see if either works for your use case for a "startup" function
[TestInitialize]
runs before all your unit tests (each)
[ClassInitialize]
runs once, the only official doc I can find these days is older...
ClassInitializeAttribute Class
Identifies a method that contains code that must be used before any of
the tests in the test class have run and to allocate resources to be
used by the test class. This class cannot be inherited.
Remarks
When run in a load test, the method marked with this attribute
will run once, and any initialization operations it performs will
apply to the entire test. If you need to do initialization operations
once for every virtual user iteration in the test, use the
TestInitializeAttribute.
The order that methods will be run is:
Methods marked with the AssemblyInitializeAttribute.
Methods marked with the ClassInitializeAttribute.
Methods marked with the TestInitializeAttribute.
Methods marked with the TestMethodAttribute.
Only one method in a class may be decorated with this attribute.
Important
This attribute should not be used on ASP.NET unit tests, that is, any
test with [HostType("ASP.NET")] attribute. Because of the stateless
nature of IIS and ASP.NET, a method decorated with this attribute may
be called more than once per test run.
Hth
It depends on which test framework you're using.
EDIT: I see now that you're using xUnit, but I'll leave the entire answer in case it's helpful to someone else.
xUnit
You can check this answer, which talks about how to create a global setup/teardown for a set of tests. To sum up that answer, if you create a constructor for your unit test class in Xunit, that method will be called before each test method. It also states:
A more optimized version would use the IClassFixture interface to
ensure that the global initialization/teardown functionality is only
called once. For this version, you don't extends a base class from
your test class but implement the IClassFixture interface where T
refers to your fixture class:
using Xunit;
public class TestsFixture : IDisposable {
public TestsFixture ()
{
// Do "global" initialization here; Only called once.
}
public void Dispose()
{
// Do "global" teardown here; Only called once.
} }
public class DummyTests : IClassFixture<TestsFixture> {
public DummyTests(TestsFixture data)
{
}
}
This will result in the constructor of TestsFixture only being run
once for every class under test. It thus depends on what you want
exactly to choose between the two methods.
If you're using NUnit it already has a OneTimeSetUp attribute you can use (docs here), like this:
[TestFixture]
public class MyTestFixture
{
[OneTimeSetUp]
public void OneTimeSetUp()
{
// Initialize things here; only called once
}
}
If you're using something other than xUnit and NUnit, check the documentation for the framework you use, and look for a one-time setup.

Do not share static properties in tests

I have to write tests for existing code with xUnit. Here is a simplified problem I faced with:
using Xunit;
namespace XUnitTestProject1
{
public class UnitTest1
{
[Fact]
public void Test1()
{
GlobalHanler.StaticProperty = "some value";
}
[Fact]
public void Test2()
{
Assert.Null(GlobalHanler.StaticProperty);
}
}
public static class GlobalHanler
{
public static string StaticProperty;
}
}
GlobalHandler owns another object, both are static
When I run 2 tests together, Test2 fails because it can see the value that was set in Test1.
However, when I run Test2 separately, it succeeds.
My goal is to make 2 tests pass when they run together. I need somehow to reset global static property for each test separately, but I can't change the implementation of GlobalHandler
Setting StaticProperty in each test method seems not an option, because it will affect other tests running in parallel
In order to have testable code, you should first put the logic in a class that can be created as many times as needed and then use that class across your code by passing the reference.
Your production code can always use a singleton, but having no direct references to the singleton makes it testable.
Singletons and testing do not cohabit very well due to the possible side effects and unclear dependencies.
You should avoid using static. Instead of this, create a simple class and register it in your DI container as a singleton. Then you can test it easily.
Simple example:
using Microsoft.Extensions.DependencyInjection;
public class Program
{
public static void Main()
{
var serviceProvider = new ServiceCollection()
.AddSingleton<IQueueUrlProvider, QueueUrlProvider>()
.BuildServiceProvider();
Console.WriteLine(serviceProvider.GetService<IQueueUrlProvider>().QueueUrl);
}
public interface IQueueUrlProvider
{
string QueueUrl { get; }
}
public class QueueUrlProvider : IQueueUrlProvider
{
private readonly Lazy<string> _getQueueUrlLazy;
public string QueueUrl => _getQueueUrlLazy.Value;
public QueueUrlProvider()
{
_getQueueUrlLazy = new Lazy<string>(GetQueueUrl);
}
private string GetQueueUrl()
{
// get url here
return "your queue url";
}
}
}
https://dotnetfiddle.net/JjRh4q

How do I unit test a class that relies on HttpContext.GetGlobalResourceObject?

I'm trying to add tests to a webforms project. There's a static method to grab lines from resource files. One of the classes I'm trying to test, relies on grabbing text from the resource file.
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
return s;
}
}
public class ClassUnderTest
{
// returns: "Hey it's my text"
private string _eg = MyStaticClass.getText("label_in_resources.resx_file")
}
class UnitTests
{
[Test]
public void TestMyClass()
{
ClassUnderTest _cut = new ClassUnderTest();
// errors out because ClassUnderTest utilizes getText
// which requires HttpContext.GetGlobalResourceObject
// ... other stuff
}
}
Note: these are simplistic examples.
The issue is that I get a Test Failed with the message:
Message: System.NullReferenceException : Object reference not set to an instance of an object.
With my sleuthing, I've determined that this is because HttpContext is null during these tests.
I've looked at quite a few SO posts on mocking HttpContext but I don't think that I fully understand what exactly they're doing as they're typically dealing with MVC and not Webforms. Still most of them use HttpContextBase and/or HttpContextWrapper but again, I'm not sure how to implement them.
Also - I'm not directly testing the getText method. I know it works. I'm testing a class that uses it. Will mocking the HttpContext even help in this situation?
I do realize that this is sort of a hybrid of a unit test / integration test, so if this isn't the best way, I'm all ears... or.. eyes rather.
Edit
For now, I modified my getText method to return the key (name) if the result of HttpContext.GetGlobalResourceObject is null. Then I updated my tests to expect the key instead of the value. It's not ideal, but it works and allows me to continue. If there's a better way, please let me know.
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name);
return s != null ? s.ToString() : name;
}
}
Original answer with Fakes (see below for dealing with removing static)
So there's one caveat that I completely forgot about until I just tried to do this. I am pretty sure Fakes still requires Enterprise version of VS. I don't know if there's a way to get it to work with NUnit, but when you aren't able to change the code sometimes you have to just deal with it.
Here's an example of Shimming your static method. You don't need to worry about HttpContext (yet) since you aren't using it directly. Instead you can Shim your getText(string) method.
Actual Business Project
namespace FakesExample
{
public class MyStaticClass
{
public static string GetText(string name)
{
throw new NullReferenceException();
}
}
}
Your Unit Test Project
using System;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FakesExampleTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
using (ShimsContext.Create())
{
FakesExample.Fakes.ShimMyStaticClass.GetTextString = (s) =>
{
return "Go away null reference";
};
Console.WriteLine(FakesExample.MyStaticClass.GetText("foo"));
}
}
}
}
I actually ran this so I know it works. What happens is that even though GetText will always throw a NullReferenceException when called, our Shim of it returns our own custom message.
You may have to make a Visual Studio Test Project.
In your Unit Test project, right-click your reference and say "Add Fakes". It will generate all of the Shims and Stubs for your assembly.
Process of removing the static
The best solution is to actually work towards removing the static. You've already hit one major reason to not use them.
Here's how I would go about removing the static and removing the dependency on HttpContext
public interface IResourceRepository
{
string Get(string name);
}
public class HttpContextResourceRepository : IResourceRepository
{
public string Get(string name)
{
return HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
}
}
public class MyFormerStaticClass
{
IResourceRepository _resourceRepository;
public MyFormerStaticClass(IResourceRepository resourceRepository)
{
_resourceRepository = resourceRepository;
}
public string GetText(string name)
{
return _resourceRepository.Get(name);
}
}
I would then leverage Dependency Injection to handle the creation of my HttpContextResourceRepository and MyStaticClass (which should probably also be interfaced) in the actual business code.
For the unit test, I would mock the implementation
[TestFixture]
public class UnitTest1
{
[Test]
public void TestMethod1()
{
var repoMock = new Mock<IResourceRepository>();
repoMock.Setup(repository => repository.Get("foo")).Returns("My Resource Value");
var formerStatic = new MyFormerStaticClass(repoMock.Object);
Console.WriteLine(formerStatic.GetText("foo"));
}
}
Going this route, you can create any number of IResourceRepository implementations and swap them whenever you want.

VS Team Test: Multiple Test Initialize Methods in Test Class

I have unit test project called “MyClassTest” in TeamTest. This project has three TestMethods. Each method needs its own test initialization steps. But when I apply TestInitializeAttribute to three initialization methods, it says the attribute should not be used more than once. Then what should be the attribute to be used to initialize each test method in Visual Studio Team Test?
Reference:
VS Team Test: .Net Unit Testing with Excel as Data Source: Adapter Failed
How to create Startup and Cleanup script for Visual Studio Test Project?
VS 2010 Load Tests Results with custom counters
How to log unit test entry and leave in MSTest
Can a unit test project load the target application's app.config file?
According to MSDN the TestInitializeAttribute:
cannot be used more than once (AllowMultiple = false), and
cannot be inherited to create your own TestInitializeAttribute.
So, my suggestion is to create the Test Initialize Methods without the TestInitialize attribute. Then in the unique TestInitialize method check which is the current executed TestMethod and call the appropriate initialize method:
[TestClass]
public class UnitTest
{
public TestContext TestContext { get; set; }
[TestInitialize]
public void Initialize()
{
switch (TestContext.TestName)
{
case "TestMethod1":
this.IntializeTestMethod1();
break;
case "TestMethod2":
this.IntializeTestMethod2();
break;
default:
break;
}
}
[TestMethod]
public void TestMethod1()
{
}
[TestMethod]
public void TestMethod2()
{
}
public void IntializeTestMethod1()
{
//Initialize Test Method 1
}
public void IntializeTestMethod2()
{
//Initialize Test Method 2
}
}
If you have three test methods, and each method has its own initialization steps, then why are you moving initialization to method which will run before every test? Only benefit I see, is that nice switch block, which adds some lines to your source file. But it gives you drawback - looking on any of these test methods, you can't really tell in which context method will be executed. So, I use initialization method to setup only basic context, which is really used by all tests in fixture.
Just move context creation to arrange part of each method.
If you have several methods, which use common context, then just extract method, which will setup context for them, and call it at the arrange part. You also can split each context setup to several steps and reuse those steps (like it done in Given-When-Then tools like Specflow).
And, of course, creating different fixtures also option.
It's a bit of an old post, but I came up with the following which seems to work OK:
First, define an attribute class:
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class InitialiseWithAttribute : Attribute
{
public string Id { get; private set; }
public InitialiseWithAttribute(string id)
{
Id = id;
}
}
then define an extension method in some convenient utilities class:
public static bool IsInitialisedWith(this string testName, string value)
{
bool result = false;
Type testClassType = new StackFrame(1).GetMethod().DeclaringType;
MethodInfo methodInfo = testClassType.GetMethod(testName);
if (methodInfo != null)
{
InitialiseWithAttribute initialiseWithAttribute =
methodInfo.GetCustomAttribute<InitialiseWithAttribute>(true);
if (initialiseWithAttribute != null)
{
result = initialiseWithAttribute.Id == value;
}
}
return result;
}
Now write your tests, thus:
public TestContext TestContext {get; set;}
[TestInitialize]
public void TestInitialise()
{
if (TestContext.TestName.IsInitalisedWith("DoSomethingSpecial")
{
// ... Do something special
}
else
{
// ... Do something normal
}
}
[TestMethod]
[InitialiseWith("DoSomethingSpecial")]
public void MySpecialTest()
{
// The test
}
If they need three seperate inits; then they should probably be in three separate fixtures each with their own init!
At my job we pass in an argument to TestInitialize method to determine how we want initialization to work.
public partial class CommonActions
{
public void TestInitialize(bool adminTest)
{
try
{
if (adminTest)
{
//do stuff
}
We then have a standard initialization in class definition, which defaults to false.
[TestClass]
public class ProjectTestBase : FrameworkTestBase
{
public CommonActions common { get; set; } = new CommonActions();
[TestInitialize]
public void TestInitialize() => common.TestInitialize(false);
Then in the Test cases themselves you can override the TestInitialize for any test you want.
[TestClass]
public class SetReportsInAdmin : ProjectTestBase
{
[TestInitialize]
public new void TestInitialize() => common.TestInitialize(true);
We use a Boolean to tell if Admin test, which needs to have extra overhead for setup. Take this and apply whatever variables you want in a way the gives you multiple initialization through the use of one method.

How to unit test immutable class constructors?

I have an immutable class with some private fields that are set during the constructor execution. I want to unit test this constructor but I'm not sure the "best practice" in this case.
Simple Example
This class is defined in Assembly1:
public class Class2Test
{
private readonly string _StringProperty;
public Class2Test()
{
_StringProperty = ConfigurationManager.AppSettings["stringProperty"];
}
}
This class is defined in Assembly2:
[TestClass]
public class TestClass
{
[TestMethod]
public void Class2Test_Default_Constructor()
{
Class2Test x = new Class2Test();
//what do I assert to validate that the field was set properly?
}
}
EDIT 1: I have answered this question with a potential solution but I'm not sure if it's the "right way to go". So if you think you have a better idea please post it.
This example isn't really worth testing, but assume the constructor has some more complex logic. Is the best approach to avoid testing the constructor and to just assume it works if all the tests for the methods on the class work?
EDIT 2: Looks like I made the sample a little to simple. I have updated it with a more reasonable situation.
Nothing, unless you are using that field. You don't want over-specification via tests. In other words, there is no need to test that the assignment operator works.
If you are using that field in a method or something, call that method and assert on that.
Edit:
assume the constructor has some more complex logic
You shouldn't be performing any logic in constructors.
Edit 2:
public Class2Test()
{
_StringProperty = ConfigurationManager.AppSettings["stringProperty"];
}
Don't do that! =) Your simple unit test has now become an integration test because it depends on the successful operation of more than one class. Write a class that handles configuration values. WebConfigSettingsReader could be the name, and it should encapsulate the ConfigurationManager.AppSettings call. Pass an instance of that SettingsReader class into the constructor of Class2Test. Then, in your unit test, you can mock your WebConfigSettingsReader and stub out a response to any calls you might make to it.
I have properly enabled [InternalsVisibleTo] on Assembly1 (code) so that there is a trust relationship with Assembly2 (tests).
public class Class2Test
{
private readonly string _StringProperty;
internal string StringProperty { get { return _StringProperty; } }
public Class2Test(string stringProperty)
{
_StringProperty = stringProperty;
}
}
Which allows me to assert this:
Assert.AreEqual(x.StringProperty, "something");
The only thing I don't really like about this is that it's not clear (without a comment) when you are just looking at Class2Test what the purpose of the internal property is.
Additional thoughts would be greatly appreciated.
In your edit, you now have a dependancy on ConfigurationManager that is hard to test.
One suggestion is to extract an interface to it and then make the Class2Test ctor take an IConfigManager instance as a parameter. Now you can use a fake/mock object to set up its state, such that any methods that rely on Configuration can be tested to see if they utilize the correct values...
public interface IConfigManager
{
string FooSetting { get; set; }
}
public class Class2Test
{
private IConfigManager _config;
public Class2Test(IConfigManager configManager)
{
_config = configManager;
}
public void methodToTest()
{
//do something important with ConfigManager.FooSetting
var important = _config.FooSetting;
return important;
}
}
[TestClass]
public class When_doing_something_important
{
[TestMethod]
public void Should_use_configuration_values()
{
IConfigManager fake = new FakeConfigurationManager();
//setup state
fake.FooSetting = "foo";
var sut = new Class2Test(fake);
Assert.AreEqual("foo", sut.methodToTest());
}
}

Categories