(C#, Rhino Mocks, MbUnit).
I have a class called AccountManager that has a RegisterUser() method. This method returns void but does throw an exception for any errors. AccountManager calls into an IDataRepository calling its AddUser() method to do a database insert.
I'm mocking the IDataRepository using a Rhino Mock and throwing and exception for a given set of arguments simulating the exception being raised in the repository.
[Test]
public void RegisterKnownUser()
{
MockRepository mocks = new MockRepository();
IDataRepository dataRepository = mocks.StrictMock<IDataRepository>();
using (mocks.Record())
{
Expect.Call(() => dataRepository.AddUser("abc", "abc", "abc#abc.com", "a", "bc")).Throw(
new InvalidOperationException());
}
using (mocks.Playback())
{
AccountManager manager = new AccountManager(dataRepository);
Assert.Throws(typeof (InvalidOperationException), () => manager.RegisterUser("abc", "abc", "abc#abc.com", "a", "bc"));
}
}
This test works fine.
My question is what to do about the situation where the args supplied to RegisterUser are correct and valid. The real IDataRepository would not return anything nor would it thrown any exceptions. So in short AccountManager's state would not have changed. Does this mean I don't need to test AccountManager.RegisterUser when it would result in nothing I can observe directly in the class and method under test. Testing against state in the mock smells a bit to me. I think as long as I test IDataRepository.AddUser seperately then I shouldn't need to test AccountManager.RegisterUser for inputs that would result in nothing observable in the class.
Thanks in advance.
If AccountManager calls into DataPrepository, then your test case still validates something. The record/playback here validates that a call is made into it. If the call is not made, the test case will fail. If it is made twice/with the wrong args, it will fail.
This may be a very basic test case, but it is still a good one, and doesn't require you to place state in the mock object.
You may want to test the method with valid arguments to ensure it does not throw any exception. In other words, you cannot observe state change or use a return value (since it's void), but you can observe that the method ran without exceptions.
By the way, if the method does not return a value nor change AccountManager state, it does change something otherwise (if not, than you should probably remove from your code the method which does nothing at all).
For example, it may affect DataRepository. Or add a record in the database. In this case, you can test at least if the data is changed or if the record is added successfully. Or it may log an event saying that the new user was registered, so you will be able, in your tests, to check if the log event is here.
I think as long as I test IDataRepository.AddUser seperately then I shouldn't need to test AccountManager.RegisterUser for inputs that would result in nothing observable in the class
If AccountManager.RegisterUser adds nothing to IDataRepository.AddUser except arguments enforcement, than yes, you don't have to test it if you already tested IDataRepository.AddUser. If it checks arguments, calls AddUser and does something else, it will be good to check if what it does is correct.
Let's say you have:
public void AddUser(string userName, string userMail, string passwordHash)
{
// [...] Add a user to the database.
}
public void RegisterUser(string userName, string userMail, string passwordHash)
{
if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException(...);
if (string.IsNullOrEmpty(userMail)) throw new ArgumentNullException(...);
if (string.IsNullOrEmpty(passwordHash)) throw new ArgumentNullException(...);
if (!Checks.IsValidMail(userMail)) throw new ArgumentException(...);
this.AddUser(userName, userMail, passwordHash);
this.SaveToLog(LogEvent.UserRegistered, userName, this.IPAddress);
}
In RegisterUser, you test the first four lines by passing wrong arguments and expecting an exception. The fifth line must not be tested, since you already tested AddUser. Finally, the sixth line must be tested to ensure that when you call RegisterUser with valid arguments, the log entry is created.
Related
I found, that simple Unit test
[TestMethod()]
[ExpectedException(typeof(ArgumentException))]
public void UT_UU()
{
}
gives fault with
Message: Test method did not throw expected exception
System.ArgumentException.
I successfully use [ExpetedException] to test error message output, however, any checking with Assert of side variables in the Unit Test gives it faulted.
Could I somehow decorate my test to avoid it? Or it is "political error"?
with [ExpectedException(typeof(ArgumentException))] your unit test will pass only when the method under test generates an exception of similar type you specified. In your case ArgumentException else it will fail with the message you have posted.
So essentially, you will have to fail your test method with that injection by means of injecting that exception. Currently your test method doesn't throw the expected exception (it actually doesn't perform anything)
For example below test method would pass
[TestMethod()]
[ExpectedException(typeof(ArgumentException))]
public void UT_UU()
{
throw new ArgumentException();
}
Using Assert statements in the body of the test that is decorated with ExpectedException doesn't really fit the pattern well if your test is isolated enough to only be testing one thing. If you follow the "Arrange, Act, Assert" pattern, then Assert is in this case handled by the ExpectedExceptionAttribute itself and the last line of code in the body of the test itself would be the "Act" because it should cause the exception to occur. If you need to know something more specific about the thrown exception to ensure that the system is meeting behavioral expectations, then I would use a try/catch within the test itself to be able to provide more granular inspection:
[TestMethod]
public void UT_UU()
{
// Arrange
var subject = new Foo();
try
{
// Act
subject.Bar();
}
catch(ArgumentException ae)
{
Assert.AreEqual("my message", ae.Message);
return;
}
catch(Exception e)
{
Assert.Fail("Thrown exception was of wrong type"); // would provide more detail here
}
Assert.Fail("exception should have been thrown");
}
Obviously just using ExpectedException is nice because it lets you right a very clean test without extra noise. Alternatively, if you were going to re-use this type of test you could write a derivative of ExpectedException that lets you specify other characteristics (like Message) to check instead of just the type.
I have method works fine when I call it from other places in the code, I added unit test to test this method and when it's being called from the test method it throws exception in the very first line.
public static void PostToAzureQueue(AlertNotification alertNotification)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueClient.GetQueueReference("activealertsqueue");
queue.CreateIfNotExists();
CloudQueueMessage message = new CloudQueueMessage(alertNotification.Serialize());
queue.AddMessage(message);
}
And here is the test method
public void VerifyPostToAzureQueue()
{
try
{
AlertNotification alertNotification = new AlertNotification();
alertNotification.DataCenters = "TestCenter";
alertNotification.TimeStamp = DateTime.Now;
Utils.PostToAzureQueue(alertNotification);
Assert.IsTrue(true);
}
catch
{
Assert.Fail();
}
}
When I hard code the connection string in the first line in the method, it passed this line but failed in the 2nd line.
The method works just fine when I call it from anywhere else.
Please note that the test method is in separate test project.
Based on your comments above, you are seeing a null reference exception because your code, probably this line:
CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"))
isn't able to find a connection string. As you noted, your test function is in a separate project from your production code, so the StorageConnectionString probably isn't in an accessible configuration file.
Which nicely demonstrates why it's a bad idea to build connection objects in your code where you're going to use it. Your current PostToAzureQueue method does multiple things:
It gets connection settings for your account.
It creates a client for your account.
It creates an activealertsqueue if it doesn't exist.
It sends a message to that queue.
This violates the Single Responsibility Principle. This method should do one thing: send a message to a queue. You should refactor this method to do only that one thing, and then provide it with the tools that it needs to do that thing. So it would look something like:
public static void PostToAzureQueue(AlertNotification alertNotification, CloudQueueClient client)
{
var queue = client.GetQueueReference("activealertsqueue");
queue.AddMessage(new CloudQueueMessage(alertNotification.Serialize()));
}
Your client should be created externally and injected into your code (really it should be injected into the parent class and not this method, but that's a different discussion). You can then handle any exceptions (say, a QueueNotExists or whatever would be thrown if activealertsqueue doesn't exist) and retry logic where PostToAzureQueue is called. By extracting these pieces of functionality from this method you will simplify this method and make it more testable.
Why won't this test method work? I keep getting requires a return value or an exception to throw.
public AuthenticateResponse Authenticate(string username, string password)
{
string response = GetResponse(GetUrl(username, password).ToString());
return ParseResponse(response);
}
[TestMethod()]
[ExpectedException(typeof(XmlException))]
public void Authenticate_BadXml_ReturnException()
{
MockRepository mockRepository = new MockRepository();
SSO sso = mockRepository.Stub<SSO>();
sso.Stub(t => t.GetResponse("")).Return("<test>d");
AuthenticateResponse response = sso.Authenticate("test", "test");
}
Your repository is still in "record" mode. You're mixing record/replay semantics (the "old" way of doing things) with the newer AAA (arrange/act/assert) style.
Instead of creating your own repository, simply use:
var sso = MockRepository.GeneateStub<SSO>();
Everything should work fine now.
Your last line is calling the Authenticate method on your stub object, you haven't set up a return or value or exception to throw when calling it, so Rhino Mocks doesn't know what the stub should do and it causes an error. You probably don't want to call a method on your stub - that seems kind of pointless to me, is there another object (that you're actually testing in this test) that you should be calling a method on?
Is that your whole test? If so, your test makes no sense. The only object in your test is the one you're stubbing--where is the subject of the test?
If you're trying to test the SSO class, you absolutely never want to mock/stub it. If SSO has one or more dependencies, use the mocking framework to set up canned interactions between those dependencies and your SUT. That is the exact purpose of a mocking framework.
I'm currently building a class using TDD. The class is responsible for waiting for a specific window to become active, and then firing some method.
I'm using the AutoIt COM library (for more information about AutoIt look here) since the behavior I want is actually a single method in AutoIt.
The code is pretty much as the following:
public class WindowMonitor
{
private readonly IAutoItX3 _autoItLib;
public WindowMonitor(IAutoItX3 autoItLib)
{
_autoItLib = autoItLib;
}
public void Run() // indefinitely
{
while(true)
{
_autoItLib.WinWaitActive("Open File", "", 0);
// Do stuff now that the window named "Open File" is finally active.
}
}
}
As you can see the AutoIt COM library implements an interface wich I can mock (Using NUnit and Rhino Mocks):
[TestFixture]
public class When_running_the_monitor
{
WindowMonitor subject;
IAutoItX3 mockAutoItLibrary;
AutoResetEvent continueWinWaitActive;
AutoResetEvent winWaitActiveIsCalled;
[SetUp]
public void Setup()
{
// Arrange
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
mockAutoItLib.Stub(m => m.WinWaitActive("", "", 0))
.IgnoreArguments()
.Do((Func<string, string, int, int>) ((a, b, c) =>
{
winWaitActiveIsCalled.Set();
continueWinWaitActive.WaitOne();
return 1;
}));
subject = new Subject(mockAutoItLibrary)
// Act
new Thread(new ThreadStart(subject.Run)).Start();
winWaitActiveIsCalled.WaitOne();
}
// Assert
[Test]
[Timeout(1000)]
public void should_call_winWaitActive()
{
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Bestand selecteren", "", 0));
}
[Test]
[Timeout(1000)]
public void ensure_that_nothing_is_done_while_window_is_not_active_yet()
{
// When you do an "AssertWasCalled" for the actions when the window becomes active, put an equivalent "AssertWasNotCalled" here.
}
}
The problem is, the first test keeps timing out. I have already found out that when the stub "WinWaitActive" is called, it blocks (as intended, on the seperate thread), and when the "AssertWasCalled" is called after that, execution never returns.
I'm at a loss how to proceed, and I couldn't find any examples of mocking out a blocking call.
So in conclusion:
Is there a way to mock a blocking call without making the tests timeout?
(P.S. I'm less interested in changing the design (i.e. "Don't use a blocking call") since it may be possible to do that here, but I'm sure there are cases where it's a lot harder to change the design, and I'm interested in the more general solution. But if it's simply impossible to mock blocking calls, suggestions like that are more that welcome!)
Not sure if I understand the problem.
Your code is just calling a method on the mock (WinWaitActive). Of course, it can't proceed before the call returns. This is in the nature of the programming language and nothing you need to test.
So if you test that WinWaitActive gets called, your test is done. You could test if WinWaitActive gets called before anything else, but this requires ordered expectations, which requires the old style rhino mocks syntax and is usually not worth to do.
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
subject = new Subject(mockAutoItLibrary)
subject.Run()
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
You don't do anything else then calling a method ... so there isn't anything else to test.
Edit: exit the infinite loop
You could make it exit the infinite loop by throwing an exception from the mocks. This is not very nice, but it avoids having all this multi-threading stuff in the unit test.
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
// make loop throw an exception on second call
// to exit the infinite loop
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Repeat.Once();
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Throw(new StopInfiniteLoopException());
subject = new Subject(mockAutoItLibrary)
try
{
subject.Run()
}
catch(StopInfiniteLoopException)
{} // expected exception thrown by mock
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
Your Test only contains a call to the mocked method. Therefore it tests only your mock instead of any real code, which is an odd thing to do. We might need a bit more context to understand the problem.
Use Thread.Sleep() instead of AutoResetEvents: Since you are mocking the COM object that does the blocking window-active check, you can just wait for some time to mimick the behavior, and then make sure that the window is indeed active by making it active programmatically. How you block should not be important in the test, only that you block for some significant time.
Although from your code it is not clear how winWaitActiveIsCancelled and continueWinWaitActive contribute, I suspect they should be left out of the WinWaitActive mock. Replace them with a Thread.Sleep(500).
I have a test method that is run. When the method generates an exception I want to know what the name of the test was and the exception content.
In the teardown for the test I want to get access to this information. How would I get access to it from the [TearDown] attributed method?
You can access text context objects in test tear down method
[TearDown]
public void TestTearDown()
{
// inc. class name
var fullNameOfTheMethod = NUnit.Framework.TestContext.CurrentContext.Test.FullName;
// method name only
var methodName = NUnit.Framework.TestContext.CurrentContext.Test.Name;
// the state of the test execution
var state = NUnit.Framework.TestContext.CurrentContext.Result.State; // TestState enum
}
I don't know which version was first to support it, but mine is 24.
I don't think there's a good way built in to nunit, but it's not a hard problem to resolve. Just wrap your tests in a try/catch block, catch any exceptions, and save them (and the test name) to a private member variable in your test class. Then you've got access from your TearDown method.
Not particularly elegant, but it works.
Another solution would be to use a template method and run all tests using this method. For example:
// template method
void Execute(Action test)
{
try
{
test();
}
catch (Exception e)
{
// handle exception here
throw;
}
}
[Test]
public void Test()
{
Execute(() =>
{
// your test here
});
}
This pattern is particularly useful when your test uses some resources that must be initialized before test and disposed after test (e.g. temporary file). In that case, you can use a type parameter in test delegate.
Another advantage is that you can easily let the test run on different thread, using different culture etc.
Disadvantage is clear: it forces you to use lambda method in every test.
OPTION 1: I don't think you can. Or rather, I don't know that you can. How I approach this need is to use a try/catch on the specific tests, do what I want with the exception and then throw again within the catch block so that the test could fail.
try{
// do something that can potentially throw;
}
catch(Exception ex){
// do something interesting with the ex;
throw;
}
OPTION 2: If you've not gone too far along, you may want to use xUnit which has a different exception expectation model and may provide some of the control you are looking for.