I'm using NUnit and Rhino Mocks. I use the AAA-syntax and I do the Arrange and Act in the setup method, and every Test method is an Assert.
[TestFixture]
public class When_subSystem_throws_exception
{
SomeClass subject; // System under test
[SetUp]
public void Setup()
{
// Arrange
IDependency dependency = MockRepository.GenerateStub<IDependency>();
dependency.Stub(m => m.DoStuff()).Throw(new Exception()); // This method is called from within SomeMethod()
subject = new SomeClass(dependency);
// Act
subject.SomeMethod("Invalid Input");
}
// Assert
[Test]
public void should_log_an_exception_to_the_logger()
{
// Do stuff to verify that an exception has been logged
}
// More tests
}
As you might expect, the code in SomeMethod() throws an exception (as expected), wich makes every test fail (unwanted). I workaround this by doing
try
{
// Act
subject.SomeMethod("Invalid Input");
}
catch(Exception ex)
{
// Swallow, this exception is expected.
}
But that is just ugly.
What I would like to be able to do is
[SetUp]
[ExpectedException] // <-- this works for Test methods, but not for SetUp methods
public void Setup()
{
// etc...
}
but I can't find anything like it.
Do you know of anything?
I don't think using an attribute like ExpectedException is a good idea.
SetUp is to prepare something for the test methods, it shouldn't throw exception.
If it must throw, and you want to limit the code line number. Then put them into one line like below:
try { subject.SomeMethod("Invalid Input"); }catch { }
It doesn't work in Setup for a reason, not because of NUnit's bug.
It's a very bad practice for a unit-test to have exception throwing inside the SetUp method. If you are testing a particular scenario where a exception is the expected result, it should be done inside a [Test] method. You should rearrange your code subsequently.
Your "act" step should be in the test method not the setup.
The setup is for setting up pre-requisite conditions and common objects for the test(s) - i.e. common or repeated "arrange" steps.
Each test method should "act" and "assert" individually (and may also need additional "arrange" steps specific to the test).
Related
I have a logger class, which purpose is to be called from whatever class in my solution, who decides to log something.
I added an interface, which is why I applied a singleton pattern, and didn't use a static class.
My LogManager implementation (singleton):
https://pastebin.com/NHKmbj9c
I wanted to write simple unit tests, which are supposed to use local variables, testing the functionality of each ILogger methods, but as soon as my first Unit has passed, the Singleton will stay initialized in context, making subsequent unit tests to fail (while they are trying to Initialize the singleton...).
Unit Test:
[TestClass]
public class LogManagerTests
{
[TestMethod]
public void Error_ExpectedErrorLevel_ShouldBe_Error()
{
// Arrange
var actualLevel = ErrorLevel.Warning;
const ErrorLevel expectedLevel = ErrorLevel.Error;
var iLogger = LogManager.GetInstance;
iLogger.Initialize((level, msg) => { actualLevel = level; }, null);
// Act
iLogger.Error(new Exception(), string.Empty);
// Assert
Assert.AreEqual(expectedLevel, actualLevel);
}
[TestMethod]
public void Debug_ExpectedErrorLevel_ShouldBe_Verbose()
{
// Arrange
var actualLevel = ErrorLevel.Warning;
const ErrorLevel expectedLevel = ErrorLevel.Verbose;
var iLogger = LogManager.GetInstance;
iLogger.Initialize(null, (level, msg, ex) => { actualLevel = level; });
// Act
iLogger.Debug(string.Empty);
// Assert
Assert.AreEqual(expectedLevel, actualLevel);
}
}
Another tought is to initialize the LogManager as a private global variable within my TestClass, but this could give race conditions if the Unit test runs async, as multiple methods then will access the same output variable, which may override each others.
Is it possible to UnitTest a singleton in any way?
The design does not allow me to refactor the LogManager, and remove the singleton pattern from it.
It's possible to unit test a singleton, you just need to think about it differently. Don't try so hard to change your methodology to fit the test. Think about creating a method that is used only for testing, LogManager.Uninitialize().
Call this after every test in this group of tests to ensure your singleton is set back to a testable state.
[TestCleanup()]
public void Cleanup()
{
LogManager.Uninitialize();
}
It may not be pure but I think it's fine to write in a diagnostics method every once in a while. It's better than having bad test coverage where you need good test coverage.
How can I pass types into my unit tests?
public void MethodUnderTest()
{
try
{
var businessService = _businessService.DoWork();
}
catch (SomeException exception)
{
//do some stuff
}
catch (SomeOtherException exception)
{
//do other stuff
}
}
My unit test should be something like this:
[TestCase(typeof(SomeException))]
[TestCase(typeof(SomeOtherException))]
public void UnitTest(Exception exception)
{
_businessService.Setup(x=>x.DoWork).Throws.InstanceOf<exception>();
//verify that when we called DoWork, that the logic inside of one of the catches was executed
}
One way this can be implemented would be, by utilizing inferred generics ..
you will have a test case source in your test fixture.
public static List< Exception > Exceptions => new List< Exception >
{
new InvalidOperationException(),
new OverflowException()
};
and then modify your unit test method as :
[Test]
[TestCaseSource(nameof( Exceptions ))]
public void UnitTest<T>( T exception ) where T : Exception, new(){
_businessService.Setup(x=>x.DoWork).Throws.InstanceOf<T>();
//verify that when we called DoWork, that the logic inside of one of the catches was executed
}
Then the code would infer the types from the instance of the exceptions in the test case source. I can't think of a way to do this with out instantiating the exceptions ...
You haven't said what you have tried that didn't work. On the surface, it appears easy enough, but perhaps I don't understand what you want to do.
The example unit test you show is incorrect. It takes an Exception as an argument, but you are giving it a Type. Based on your title, the test method should accept a type. Then do something like...
[TestCase(typeof(SomeException))]
[TestCase(typeof(SomeOtherException))]
public void UnitTest(Type exceptionType)
{
Assert.That(()=>_businessService.Setup(x=>x.DoWork),
Throws.InstanceOf(exceptionType));
}
```
Did I misunderstand the problem?
How can I simulate an exception being thrown in C# unit tests?
I want to be able to have 100% coverage of my code, but I can't test the code with exceptions that may occur. For example I cannot simulate a power faluire that may occur.
For example:
public void MyMethod()
{
try
{
...
}
catch(OutOfMemoryException e)
{
...
}
catch(RandomErrorFromDatabaseLayer e)
{
...
}
}
I want to be able to simulate any kind of exception that is in this method and should be caught.
Are there any libraries that may help me in this matter?
Edit 1:
Any help in accomplishing what I asked with Moq?
You need to create a mock object that stands in for the real objects that can throw these exceptions. Then you can create tests that simply are something like this:
public void ExampleMethod()
{
throw new OutOfMemoryException();
}
If you are using a dependency injection framework it makes replacing the real code with the mock code much easier.
What you need is stub - an object that will simulate certain conditions for your code. For testing purposes, you usually replace real object implementation with stub (or other type of faked object). In your case, consider:
public class MyClass
{
private IDataProvider dataProvider;
public void MyMethod()
{
try
{
this.dataProvider.GetData();
}
catch (OutOfMemoryException)
{
}
}
}
Now, class you are testing should be configurable at some level - so that you can easily replace real DataProvider implementation with stubbed/faked one when testing (like you said, you don't want to destroy your DB - nobody wants!). This can be achieved for example by constructor injection (or in fact, any other dependency injection technique).
Your test then is trivial (some made-up requirement to test when exception is thrown):
[Test]
public void MyMethod_DataProviderThrowsOutOfMemoryException_LogsError()
{
var dataProviderMock = new Mock<IDataProvider>();
dataProviderMock
.Setup(dp => dp.GetData())
.Throws<OutOfMemoryException>();
var myClass = new MyClass(dataProviderMock);
myClass.MyMethod();
// assert whatever needs to be checked
}
IMHO, Rhino Mocks produces an unclear diagnostic message when AssertWasCalled is used in order to verify that a method has been called with a specific argument.
Example:
interface ISomeInterface
{
void Write(string s);
}
[TestFixture]
public class SomeTests
{
[Test]
public void WriteShouldBeCalledWithCorrectArguments()
{
// Arrange
var mock = MockRepository.GenerateMock<ISomeInterface>();
var sut = new SomeClass(mock);
// Act
sut.DoSomething();
// Assert
mock.AssertWasCalled(x => x.Write(Arg<string>.Is.Equal("hello")));
}
}
Now, if the test fails with this message...
Rhino.Mocks.Exceptions.ExpectationViolationException : ISomeInterface.Write(equal to hello); Expected #1, Actual #0.
... you cannot know if it fails because
A. 'Write' is never invoked -or-
B. 'Write' is in fact invoked but with the incorrect argument
If B would be the cause of the failure then it would be so much clearer if the message would read something like this:
Rhino.Mocks.Exceptions.ExpectationViolationException : ISomeInterface.Write(string arg): Method was called but with the incorrect arguments: Expected: hello, Actual: bye
Can I fix this shortcoming myself (by writing custom matchers for Rhino in some way) or do I simply have to write a manual mock for this?
I've found a simple solution by using the "Matches" syntax provided by Rhino:
[Test]
public void WriteShouldBeCalledWithCorrectArguments()
{
// Arrange
var mock = MockRepository.GenerateMock<ISomeInterface>();
var sut = new SomeClass(mock);
// Act
sut.DoSomething();
// Assert
mock.AssertWasCalled(x => x.Write(Arg<string>.Matches(s => Equal(s, "hello"))));
}
private static bool Equal(string s1, string s2)
{
Assert.That(s1, Is.EqualTo(s2), "Unexpected argument");
return true;
}
Sure, it's a little clumsy but it gets the job done. If there is a better way of doing it, please let me know.
You could use GetArgumentsForCallsMadeOn to get passed arguments and assert them:
var args = mock.GetArgumentsForCallsMadeOn(x => x.Write(null), opt => opt.IgnoreArguments())[0];
Assert.AreEqual("Hello", args[0]):
If I want to test that a method throws an exception of a particular type, NUnit's ExpectedException attribute doesn't care about the actual type; if I throw a generic Exception before the method call, the test passes:
[Test, ExpectedException(typeof(TestCustomException))]
public void FirstOnEmptyEnumerable()
{
throw new Exception(); // with this, the test should fail, but it doesn't
this.emptyEnumerable.First(new TestCustomException());
}
If I want to check that the test throws the exact exception type, I have to do something manual like this:
[Test]
public void FirstOnEmptyEnumerable()
{
try
{
throw new Exception(); // now the test fails correctly.
this.emptyEnumerable.First(new TestCustomException());
}
catch (TestCustomException)
{
return;
}
Assert.Fail("Exception not thrown.");
}
Am I missing something?
I've never used ExpectedException, so I don't have any experience to share on this. An option is to Assert that it Throws directly inside the test. Something like this:
[Test]
public void FirstOnEmptyEnumerable()
{
Assert.Throws<TestCustomException>(() => this.emptyEnumerable.First(new TestCustomException()));
}
I find this approach more readable as you test for the exception exactly where you expect it to happen instead of saying "somewhere inside this function I except an exception to be thrown".
I always test for the string representation of the exception e.g.:
[Test, ExpectedException("Your.Namespace.TestCustomException")]
public void FirstOnEmptyEnumerable()
{
throw new Exception(); // with this, the test should fail, but it doesn't
this.emptyEnumerable.First(new TestCustomException());
}
Which seems to work fine for me.
If you want to use the ExpectedException(string) signature, the best practice would be to use typeof(Exception).Name and typeof(Exception).Namespace