Any ideas on this one? I'm trying to write a unit test that will delete an item and confirm that item is no longer in a repository by trying to retrieve the item by its ID which should throw a DataAccessException. However, the test keeps failing. I added a try catch block and sure enough I caught the exception I was expecting. I'm using VS Test Tools for unit testing.
[ExpectedException(typeof(DataAccessException))]
private static void NHibernateRepositoryBaseDeleteHelper<T, TKey>(T myItem, TKey myItemId)
{
MyTestRepository<T, TKey> myRepository = new MyTestRepository<T, TKey>();
myRepository.Delete(myItem);
myRepository.CommitChanges();
try
{
myRepository.GetById(myItemId, false);
}
catch (DataAccessException dae)
{
Assert.IsTrue(true);
}
}
I'll add to what Jared said by pointing out that the "ExpectedException" attribute sucks. There's no way to assert that the exception's message is correct (the "message" parameter doesn't do what you might think it does) and you can't check for multiple exceptions in one test.
A better solution is to do something like this:
Link
That class lets you do neat stuff like this:
[TestMethod]
public void TestAFewObviousExceptions()
{
// some setup here
ExceptionAssert.Throws("Category 47 does not exist", () =>
wallet.Categories.GetChildCategoryIds(47));
ExceptionAssert.Throws("Id Flim is not valid", () =>
wallet.Categories.IdFromName("Flim"));
}
You need to add the ExpectedException attribute onto the same method which has the TestMethod attribute. The VS Unit Test Framework will only look for an ExpectedException attribute at the entry point of a particular test.
[TestMethod]
[ExpectedException(typeof(DataAccessException))]
public void ATestMethod() {
...
NHibernateRepositoryBaseDeleteHelper(itemValue, keyValue);
}
You are munging up your delete method first of all. I would have a separate delete method and test method. Yes, you are testing the delete, but really you are testing the behavior that is associated with delete. There are probably additional tests here.
As this is part of what appears to be an autogenerated test, I would not add to the same repository object in that test, but would perform my test(s) in their own test methods and use the delete as part of the set up for the class. That will certainly separate the test from the delete.
Hope this helps.
Related
Here is specific case. I want to test this Assert.ThrowsException<DbException>(() => { MyMethod(0, 100); });
The problem is that exception thrown is SqlException. Why do I want to test base exception? Because I want a unified test for any of my 3 DB providers. The exception sometimes is OracleException or MySqlException. All 3 providers exceptions derive from DbException
Is there a way to test it nicely, using the Microsoft Unit Test framework?
According to the documentation for Assert.ThrowsException this is expected. However, if you're able to use Fluent Assertions, this is in fact very easy to achieve.
Action action = () => MyMethod(0, 100);
action.Should().Throw<DbException>(); // add some more checks
// this would mimic the behavior of Assert.ThrowsException, which should fail.
action.Should().ThrowExactly<DbException>();
See also the tips on improving assertions under Tips/Exceptions.
The alternative would be to use regular try...catch like in the example below. You need to make sure that you capture all the code path' and don't accidentally succeed:
/// <summary>
/// Catching a base exception class just by using <see cref="Assert"/>.
/// Do not use <see cref="ExpectedExceptionAttribute"/>, since it doesn't
/// provide any type of validation.
/// </summary>
[TestMethod]
public void CatchAderivedExceptionTheAssertWay()
{
try
{
// A test method that throws an exception.
Action action = () => throw new ArgumentNullException("param1");
action();
}
catch (ArgumentException e)
{
// This will catch any exception derived from ArgumentException.
// Do some validation to ensure the right thing is caught,
// like checking the parameter name.
if (!e.ParamName.Equals("param1", StringComparison.Ordinal))
{
Assert.Fail("Reason why the validation failed.");
}
// Otherwise jump out of the test.
return;
}
Assert.Fail("Make sure the test fails, in case the code inside try doesn't throw at all.");
}
For completeness sake, there's also the ExpectedException attribute that can be added to a [TestMethod]. Due to the lack of validation options I would not recommend using it.
I'll add this question to my list of interview questions. Such a nice example.
Thanks for all the leads, one from #StephanAdler
Considering limitations of given testing framework my sensible solution was this
Exception retEx = null;
try
{
MyMethod(0, 100);
}
catch (Exception ex)
{
retEx = ex;
}
Assert.IsNotNull(retEx);
Assert.IsInstanceOfType(retEx, typeof(DbException));
Assert.IsInstanceOfType works perfectly with the base type
Using the test tools built into Visual Studio (in my case VS 2013, though I believe this extends to other versions as well), a 'TestMethod' (any method marked with a [TestMethod] attribute) can result in 1 of 3 statuses after being run:
Passed
Skipped/Inconclusive
Failed
A test is passed if it runs to completion with no uncaught exceptions. A test fails it throws an uncaught exception. A test is inconclusive if it throws a special type of uncaught exception: AssertInconclusiveException.
My question is, is it possible (in, say, a [TestCleanup] method) to treat an custom uncaught exception similarly to the AssertInconclusiveException and set the test status to 'Inconclusive' instead of 'Failed'? Or is the recognition of AssertInconclusiveException as a special exception built into Visual Studio itself? What I'm looking for, in rough pseudocode form, is roughly:
[TestCleanup]
public void TestCleanup()
{
if(this.TestContext.CurrentTestOutcome == UnitTestOutcome.Failed
&& this.TestContext.UncaughtException.GetType() == typeof(MyCustomException))
{
this.TestContext.CurrentTestOutcome = UnitTestOutcome.Inconclusive;
}
}
This would be used as part of an integration test suite to mark a test as inconclusive whenever the setup method for the test throws a special SetupFailureException (usually indicative of broken downstream system that is not the one under test).
I've been able to produce the desired behavior in the interim by defining:
public class SetupFailedException : AssertInconclusiveException
{
}
// example test that demonstrates desired behavior
[TestMethod]
public void TestThatFailsAsInconclusiveByThrowingUncaughtSpecialException()
{
throw new SetupFailedException();
}
But this seems messy since the thrown exception has nothing to do with an assertion and prevents custom exceptions which should fail tests as inconclusive from inheriting from any other abstract class.
The Inconclusive recognition is built into the test framework, by the time you get to cleanup, it's too late to change a fail into an inconclusive.
It feels like you should really be catching the exceptions from within your integration tests anyway, since this shows that you're recognising the method your testing can throw a certain type of exception and that the right thing to do is to ignore the result in that situation.
If you need to have multiple exceptions that can be detected like this, I'd be tempted to have them implement an interface, so that the catch block can just check if any exceptions caught implement that interface.
If you wanted to minimize the impact/visibility on the rest of your test code then you could wrap the call that could fail in an action, in which case your code might look something like this:
The interface:
public interface ISomeNonCriticalException {
}
The Caller code:
public void CallPossiblyInconclusiveMethod(Action something) {
try {
something();
}
catch (Exception ex) {
if (ex is ISomeNonCriticalException) Assert.Inconclusive();
else throw;
}
}
And in your test:
CallPossiblyInconclusiveMethod(()=>SomeMethodThatMightFail());
Using VS's testing framework, I'm currently writing my tests like this:
[TestMethod]
public void TestSomething()
{
try
{
var someTestValue = _someTestClass.SomeTestMethod();
Assert.IsNotNull(someTestValue);
}
catch (Exception e)
{
Assert.Fail(e.Message);
}
}
My logic is that if an exception is thrown in SomeTestMethod(), I'll immediately terminate the test displaying the exception message through Assert.Fail(e.Message).
The "normal way" of doing things would be:
[TestMethod]
public void TestSomething()
{
var someTestValue = _someTestClass.SomeTestMethod();
Assert.IsNotNull(someTestValue);
}
Is my approach correct, or is the "normal way" correct? Am I writing redundant code ?
I'd say this is redundant, yes. If the exception is an unexpected result then the test fails. Whether it fails by throwing an exception or by failing an Assert is treated the same way by the testing framework. Basically, a failed test is a failed test.
The testing framework will already fail the test if the test method throws an exception. You're adding extra work for no added value.
You're writing redundant code. The Test method already traps exceptions and will fail the test method.
If you are expecting some exception, use this attribute:
[TestMethod]
[ExpectedException(typeof(//Here the exception you expect))] <------------
public void TestSomething()
{
//Your test code
}
This means that if the tests throw this exception, will return as passed the tests.
If you donĀ“t go to tests exceptions, then avoid try/catch blocks inside your tests. You will notice that something went wrong because the tests will fail ;)
I hope this helps
See this tutorial; there is an example unit test using the [expectedException()] attribute:
[Tutorial for ExpectedException Unit tests][1]
[1]: http://msdn.microsoft.com/en-us/library/hh694602%28v=vs.110%29.aspx#BKMK_Writing_your_tests
I have a really odd situation using Visual Studio unit testing framework. A test decorated as [TestMethod, ExpectedException(typeof(InvalidOperationException))] fails with System.InvalidOperationException.
If I remove all code from the test (to make sure it doesn't throw anything at all) - it passes. It is as if ExpectedException is not even there...
If I start an empty project with a dummy test that does nothing but throwing InvalidOperationException it totally works as expected.
Verified that neither ExpectedExceptionAttribute nor InvalidOperationException are overridden. Not sure what else to try here...
EDIT: Fixed the problem by removing reference to the Microsoft.VisualStudio.QualityTools.UnitTestFramework v10.1 and adding v10.0.
Not sure why would this matter or why other attributes worked just fine.
Personally I do not use the ExpectedExeption attribute because it does not allow you to specify exactly which statement is expected to throw the exception. For instance, there could be some problem in your test setup code that throws an InvalidOperationExeption which was not exected in your test and suddenly your test passes. Furthermore it does not allow you to inspect the Exeception, like Asserting it has the correct message.
I use the following approach
[TestMethod]
public void Test()
{
//Arrange
var sut = new ClassToTest();
sut.MethodThatShouldNotThrow();
//Act
try
{
sut.MethodToTestThatShuldThrow();
}
catch(InvalidOperationException ioex)
{
//Assert, here you could do additional Asserts on the Exception's properties
return;
}
Assert.Fail("Expected InvalidOperationException was not thrown");
}
I'm new to Nunit testing and I wanted to test the following constructor:
public class IngredientDAONHibernate : NutritionLibrary.DAO.IngredientDAO
{
private Configuration config;
private ISessionFactory factory;
public IngredientDAONHibernate()
{
try
{
config = new Configuration();
config.AddClass(typeof(NutritionLibrary.Entity.Ingredient));
config.AddClass(typeof(Entity.Nutrient));
config.AddClass(typeof(Entity.NutrientIngredient));
factory = config.BuildSessionFactory();
}
catch (Exception e)
{
// logger.Error("Exception Occured", e);
}
}
The test stub is as follows:
[TestMethod()]
public void IngredientDAONHibernateConstructorTest()
{
IngredientDAONHibernate target = new IngredientDAONHibernate();
}
Could someone help me with some tips as to how I can get started? Thanks!
I would suggest that you don't catch all the exceptions, but, if there are certain you want to catch and ignore then just do those, otherwise it is harder to tell if you have a problem.
I tend not to test the constructor, unless it is doing quite a bit, and it will be obvious if there is a problem when doing the other unit tests, as, if the constructor fails you should see by the exception, and by the fact that all the tests will be failing.
If you want to test this constructor, limit your exceptions and just ensure that there is no exception when you run the test.
Let me turn the question back on to you.. How do you know if the constructor executed as intended ?
Normally constructors are trivial.. but here it seems that you have some third party lib interfacing code that you need some confidence with.
If you only want to test that there are no exceptions raised from within the constructor... then Extract a logger interface. Now in your test pass in a mock logger (a fake can also suffice), which should help you to sense if an exception was logged.
[TestMethod()]
public void IngredientDAONHibernateConstructorTest()
{
_errorLogged = false;
ILogger logger = this; // make test fixture implement the logger interface ; self-shunt
IngredientDAONHibernate target = new IngredientDAONHibernate(logger);
Assert.IsNotNull(target);
Assert.IsFalse(_errorLogged,
String.Format("ERROR! Constructor has thrown {0}", _loggedException) );
}
bool _errorLogged;
Exception _loggedException;
public void Error(string message, Exception e)
{
_errorLogged = true;
_loggedException = e;
}
Like everyone else, I would caution against catching Exception. The documentation should tell you what exceptions can be expected and you could write specific Catch clauses for each of them, if that made sense.
Leaving that aside, your tests should verify that your objects are in the state you expect. Given what we can see, all you can do is test that it's not null. If you can force an exception, you could test that the logger gets the exception message. If there was a public property that gave access to your factory, you would want to test that (not null, perhaps other things) and likewise with the config field. For that, if you have access to the added classes, you could test not null and count==3. If the exact objects are important, you could test that they are there. It's always tricky to decide how much to trust third-party stuff. Generally, I do unless I get evidence that I shouldn't.
When it comes to testing methods, test for each parameter whatever is possible. So, for a string, test null and emptystring plus relevant (valid and invalid) values. If you're expecting alphanumerics, test special chars as well. If data has boundaries test values on and either side of the boundary(ies) plus typical values. E.g. if you're expecting an int between 0 and 10, test -1, 0, 1, 5, 9, 10, 11. It only takes seconds to write but it can save you hours in two years when you're trying to fix a bug.