Asserting an exception thrown from a mock object constructor
Solution 1
If you have to have the class an abstract one, we should then just implement it as it's meant to be (simplicity): MSDN: an abstract class
So, agreeing (with alexanderb)that a mock is probably not needed here and also with Stecy on the .Throws NUnit Assert extension, you can create a class in the test that calls the base class as follows:
using System;
using System.IO;
namespace fileFotFoundException {
public abstract class MyFile {
protected MyFile(String fullPathToFile) {
if (!File.Exists(fullPathToFile)) throw new FileNotFoundException();
}
}
}
namespace fileFotFoundExceptionTests {
using fileFotFoundException;
using NUnit.Framework;
public class SubClass : MyFile {
public SubClass(String fullPathToFile) : base(fullPathToFile) {
// If we have to have it as an abstract class...
}
}
[TestFixture]
public class MyFileTests {
[Test]
public void MyFile_CreationWithNonexistingPath_ExceptionThrown() {
const string nonExistingPath = "C:\\does\\not\\exist\\file.ext";
Assert.Throws<FileNotFoundException>(() => new SubClass(nonExistingPath));
}
}
}
Solution 2
The constructor will not be called until you reference mock.Object. That should trigger the exception you're expecting.
On a side note, it's generally bad practice to have a constructor throw exceptions other than usage exceptions (such as the various ArgumentException derivatives.) Most developers don't expect 'new' to throw an exception unless they've done something very wrong; a file not existing is the kind of exception that can legitimately happen beyond the control of the program, so you might want to make this a static factory method instead like "FromFileName". EDIT: Given that this is a base class constructor, that's not really applicable either, so you may want to consider where is the best place to institute this check. After all, the file may cease existing at any point, so it might not even make sense to check in the constructor (you'll need to check in all relevant methods anyway.)
Solution 3
I faced similar problem today. I worked it out using the following solution:
[Test]
[ExpectedException(typeof(System.IO.FileNotFoundException))]
public void MyFileType_CreationWithNonexistingPath_ExceptionThrown()
{
String nonexistingPath = "C:\\does\\not\\exist\\file.ext";
var mock = new Mock<MyFileType>(nonexistingPath);
try
{
var target = mock.Object;
}
catch(TargetInvocationException e)
{
if (e.InnerException != null)
{
throw e.InnerException;
}
throw;
}
}
Solution 4
Assuming you're using the latest version of NUnit (you should) then the ExpectedException attribute has been deprecated.
You should instead use the following:
var exception = Assert.Throws<FileNotFoundException> (() => new MyFileType (nonExistingPath));
Assert.That (exception, Is.Not.Null); // Or you can check for exception text...
No need to use a mock there. In fact, the mock does nothing interesting in your example.
Solution 5
If you tring to test MyFileType class, that it throws an exception if file does not exist, why you are creating mock. You code should be simple
[Test]
[ExpectedException(typeof(System.IO.FileNotFoundException))]
public void MyFileType_CreationWithNonexistingPath_ExceptionThrown()
{
// arrange
var nonexistingPath = "C:\\does\\not\\exist\\file.ext";
// act / assert
var mock = new MyFileType(nonexistingPath);
}
Related videos on Youtube
Noren
Updated on November 12, 2020Comments
-
Noren over 3 years
Assume: VS2010, .NET 4, C#, NUnit, Moq
I am new to TDD and came across this issue while working through a project.
Given the class:
public abstract class MyFileType { public MyFileType(String fullPathToFile) { if (!File.Exists(fullPathToFile)) { throw new FileNotFoundException(); } // method continues } }
I am trying to test it using the method:
[Test] [ExpectedException(typeof(System.IO.FileNotFoundException))] public void MyFileType_CreationWithNonexistingPath_ExceptionThrown() { String nonexistingPath = "C:\\does\\not\\exist\\file.ext"; var mock = new Mock<MyFileType>(nonexistingPath); }
The test fails and NUnit reports an exception was never thrown.
I did find a section in the NUnit docs talking about asserting with exceptions, but the examples didn't seem like what I am trying to do. I am still getting started with NUnit and Moq so I may be going about this the wrong way.
UPDATE:
To help clarify why this example uses an abstract class, it is the base class of a series file types where only the loading and disposing of the data would differ between subclassed types. My initial thought was to put the logic for open/setup into a base class since it is the same for all types.
-
Thebigcheeze about 13 yearsI'm not certain this is directly related to your problem, but changing your string definition to using the
@""
syntax is more readable and less error prone. For example, instead ofString nonexistingPath = "C:\\does\\not\\exist\\file.ext";
you could simply putString nonexistingPath = @"C:\does\not\exist\file.ext";
-
-
Noren about 13 yearsDoesn't the fact that MyFileType is abstract prohibit me from using the 'new' operator as you have shown?
-
Noren about 13 yearsI am using the latest version of NUnit, so thank you for the heads up about the deprecation. In trying your solution, I encountered the same error as I did with alexanderb's solution -- cannot create an instance of of the abstract class 'MyFileType'.
-
Alexander Beletsky about 13 yearsopps, sorry I missed that. Sure, you can't do 'new' there. But this also mean that you should not directly test this class, since it is abstract.. It has some behaviour, but this behaviour have to be tested on classes inherited from MyFileType. TDD, also could point to Desing issues. If something is hard to test, that 99% is design mistake. In you case, if class is abstract it is bad idea to put logic into constructor.
-
Noren about 13 yearsI am accepting this post as the answer since it does answer my original question.
-
Noren about 13 yearsI agree that my initial attempt at this problem had the code smell of a constructor doing too much work.
-
Pedro about 13 years+1 for not throwing exceptions from a ctor. FxCop has a rule that will flag such code.