I have some test code that seems to be running out of the correct order.
[TestClass]
public class DirTest {
public DirTest() {
Assert.AreEqual( Directory.Exists( "testpath" ), true );
}
[TestMethod]
public void TestMethod1() {
}
[ClassInitialize]
public static void InitTest( TestContext context ) {
Directory.CreateDirectory( "testpath" );
}
}
It throws an error that the directory does not exist, shouldn't ClassInitialize run before the class constructor is called or is there something I need to do that is missing. If that is not the case is there a test case other then AssemblyInitialize that can be included in the test that is called prior to the class being constructed?
-- Edit
The real issue is here, the top is a simplification.
//RealClass.cs
public class RealClass{
public RealClass( string path ){
this._path = path;
this._InitDirectory();
}
protected string _path;
protected void _InitDirectory(){
//Something that requires read from path
File.WriteAllText( this._path + "/realData.data", "some real data that needs to be created by the class" );
}
}
//DirTest.cs
[TestClass]
public class DirTest : RealClass {
public DirTest() : base( "testpath" ) {}
[TestMethod]
public void TestMethod1() {
}
[ClassInitialize]
public static void InitTest( TestContext context ) {
Directory.CreateDirectory( "testpath" );
}
}
The unit test will fail because the directory where the path is required will die before the "ClassInitialize" method is called to create the mock directory required.
-- Edit
I have come up with a work around for this, though I would still like to know if there is another way to achieve the desired result without adding more classes, and without removing the functionality of the test. I have setup a "AssemblyInitialize" to a class that just contains that static method, and told that method to fire the static methods for "ClassInitialize". It of course fires before any constructors. Though the root of the issue is still unresolved as it is not self contained but dependent on a class function to call the class setup.
You're trying to use the approach of deriving your [TestClass] from your SUT class in order to access protected methods.
Firstly: is what you're doing really necessary? In the code you posted, there are no tests that explicitly try to access a protected member of the SUT. So, it's possible that you're making things more difficult than they need to be.
Now, if you do actually need to test a protected member in this SUT class, then have you considered creating an class that inherits from the SUT class - a class that isn't the [TestClass]? For example:
//RealClass.cs
public class RealClass{
public RealClass( string path ){
this._path = path;
this._InitDirectory();
}
protected string _path;
protected void _InitDirectory(){
//Something that requires read from path
File.WriteAllText( this._path + "/realData.data", "some real data that needs to be created by the class" );
}
}
// TestableRealClass.cs - Only used by the unit test
public class TestableRealClass: RealClass {
public TestableRealClass(string path) : base(path) { }
public string Path {
get {
return _path;
}
}
public InitDirectory() {
_InitDirectory();
}
}
//DirTest.cs
[TestClass]
public class DirTest {
[TestMethod]
public void TestMethod1() {
var testPath = #"C:\SomePath";
if (!Directory.Exists( testPath )) {
Directory.CreateDirectory( testPath );
}
var sut = new TestableRealClass(testPath);
AssertThatTheFileContainsExpectedStuff(testPath);
}
[TestMethod]
public void TestAProtectedMember() {
var testPath = #"C:\SomePath";
if (!Directory.Exists( testPath )) {
Directory.CreateDirectory( testPath );
}
var sut = new TestableRealClass(testPath);
Assert.AreEqual(testPath, sut.Path);
}
private void AssertThatTheFileContainsExpectedStuff(string path) {
// Do the assertion...
}
}
This way you don't have to worry about the order in which the text fixture will initialize, and your tests become considerably easier to understand.
update your code as follows:
[TestClass]
public class DirTest {
public DirTest() { }
[TestMethod]
public void TestMethod1() {
}
[ClassInitialize]
public static void InitTest( TestContext context ) {
if (!Directory.Exists( "testpath" )) {
Directory.CreateDirectory( "testpath" );
}
}
}
Related
Let's say I have written a unit test to test a public method in XUnit.
[Fact]
public void MethodA_WhenSomething_ThenReturnNull()
{
// Code removed for brevity.
// Assert
}
This is MethodA.
public void MethodA() {
MethodOne();
MethodTwo();
MethodThree();
}
MethodOne, MethodTwo and MethodTree are all private method. Is there a way to skip a private method (ie MethodTwo) while running my unit test for MethodA? The reason I want to skip methodTwo is because methodTwo calling a stored procedure and it causes error in Xunit. But I know the stored procedure is running fine without issue, so it is okay for me to skip this method.
And the moment, I am using this way.
public void MethodA() {
MethodOne();
#if DEBUG == false
MethodTwo();
#endif
MethodThree();
}
If there is a better way, I wish not to put If DEBUG
This kind of problem is typically solved via Moq.Protected.
So, you need to change private accessor to protected at least for MethodTwo.
But I would suggest to change all accessors to protected.
public class SomeClass
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
protected void MethodOne() { ... }
protected void MethodTwo() { ... }
protected void MethodThree() { ... }
}
With this, the mock setup would look like this:
using Moq.Protected;
...
var mockSomeClass = new Mock<SomeClass>();
mockSomeClass.Protected()
.Setup("MethodTwo")
.Verifiable();
Additionally you can setup a Callback to write something out the test output
const string toBeMockedMethodName = "MethodTwo";
mockSomeClass.Protected()
.Setup(toBeMockedMethodName)
.Callback(() => TestContext.Progress.Writeline($"{toBeMockedMethodName} has been called."))
.Verifiable();
References:
Mocking protected members
Protected Members - Unit testing in C#
Moq - how to mock a protected method of an internal class with no parameter-less constructor
If your private method depends on some external service, then you can create make a mock of it and mark it verifiable.
[Fact]
public void MethodA_WhenSomething_ThenReturnNull()
{
var barService = new Mock<Bar>();
barService.Setup(x => x.DoSomething()).Verifiable();
///
}
public class Foo
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
private void MethodThree() => System.Console.WriteLine();
private void MethodTwo() => new Bar().DoSomething();
private void MethodOne() => System.Console.WriteLine();
}
public class Bar
{
public void DoSomething() => System.Console.WriteLine("....");
}
There are several ways that you can use to replace the private method. Let's use the MethodRedirect library.
Let's say there is the following class:
public class SomeClass
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
private void MethodOne() { }
private void MethodTwo() =>
throw new NotImplementedException();
private void MethodThree() { }
}
var sc = new SomeClass();
sc.MethodA(); // An exception will be thrown here.
The above library does not have a nuget package. Therefore, we simply copy three files from sources: Extensions.cs, MethodOperation.cs, MethodToken.cs.
Then write the following unit test:
[Fact]
public void MethodA_WhenCalled_NotThrow()
{
var sut = new SomeClass();
var fake = new Fake();
MethodInfo privateMethod = sut.GetType().GetMethod("MethodTwo", BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo redirectMethod = fake.GetType().GetMethod("Redirect", BindingFlags.Static | BindingFlags.NonPublic);
var token = privateMethod.RedirectTo(redirectMethod);
sut.MethodA(); // should not throw
token.Restore();
}
Auxiliary class whose method will be used as a replacement
public class Fake
{
static void Redirect() { }
}
When I execute my test case, it fails for path within my machine which doesn't exist and I am getting below error:
System.IO.DirectoryNotFoundException: Could not find a part of the
path 'C:\Data1'.
Do I need some kind of fake/mock here to pass the test case or do we have other way to do this?
Class
public class DemoCls
{
public void Execute()
{
string dataFolder = #"C:\\Data1";
foreach (string X in Directory.EnumerateFiles(dataFolder, "test" + "*.xml"))
{
}
}
}
Test Case
[TestClass()]
public class DemoClsTests
{
[TestMethod()]
public void ExecuteTest()
{
var X = new DemoCls();
X.Execute();
}
}
Class should be refactored to remove tight coupling to implementation concerns that make it difficult to test.
//...Creat an abstraction that provides the desired behavior as a contract
public interface IDirectoryService {
IEnumerable<string> EnumerateFiles(string path, string searchPattern);
}
A fake/mock can be created for when testing to avoid pitfalls associated with testing IO code in isolation.
A mocking framework could have been used for stubbing the dependencies, but for this example using a simple
public class FakeDIrectoryService : IDirectoryService {
IEnumerable<string> files;
public FakeDIrectoryService(IEnumerable<string> files) {
this.files = files;
}
public IEnumerable<string> EnumerateFiles(string path, string searchPattern = null) {
return files;
}
}
Class needs to be refactored now to follow Explicit Dependencies Principle via constructor and method injection.
public class DemoCls {
IDirectoryService directory;
public DemoCls(IDirectoryService directory) {
this.directory = directory;
}
public void Execute(string dataFolder) {
foreach (var x in directory.EnumerateFiles(dataFolder, "test*.xml")) {
//...
}
}
}
Test can now be properly exercised in isolation.
[TestClass()]
public class DemoClsTests {
[TestMethod()]
public void ExecuteTest() {
//Arrange
var fakePath = "C:/temp";
var fakeFiles = new[] {
#"C:\\temp\\testfakefilename1.txt",
#"C:\\temp\\testfakefilename2.txt",
#"C:\\temp\\testfakefilename3.txt"
};
var service = new FakeDIrectoryService(fakeFiles);
var sut = new DemoCls(service);
//Act
sut.Execute(fakePath);
//Assert
//perform your assertions
}
}
Finally for production code the real implementation of the file service can wrap any source, be it disk or remote service.
For example
public class FileService : IDirectoryService {
public IEnumerable<string> EnumerateFiles(string path, string searchPattern) {
return Directory.EnumerateFiles(path, searchPattern);
}
}
This is just an example of what can be done. There is a lot of room for improvement but this should get things started.
Hardcoded paths are not good to have and I would recommend two options since the class is not static.
1st
public class DemoCls
{
public void Execute(string targetPath)
{
foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
{
}
}
}
This keeps things more flexible and reusable
2nd
public class DemoCls
{
private string _targetPath;
public DemoCls(string targetPath){
_targetPath = targetPath;
}
public void Execute(string targetPath)
{
foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
{
}
}
}
This way keeps the Execute method cleaner (less preferred)
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.
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()
{
...
}
}
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()
{
}
}