Unit testing WCF Faults - c#

What's the best way to unit test expected faults from WCF services?
I am attempting to unit test a WCF service which is (correctly) throwing FaultExceptions for a certain reproducible error. The unit tests get an instance of the WCF client and call the applicable service method, which throws a FaultException.
All of that works as you would expect, but I am having difficulty unit testing this, because the fault causes the IDE to break when the error isn't caught in the service implementation. Because I am using faults, and not exceptions, I was expecting the IDE to serialize the exception and send it to the client, where it would raise an exception.
I do see that there is a configuration option to disable breaking for specific user-unhandled exceptions, but I was hoping somebody could point out a better way to achieve the same results, as this isn't easily doable in a team environment.
Here's some sample code of what the implementation currently looks like...
The unit test project has a service reference to my WCF service, and I have defined the interface as such:
[OperationContract(Name = "DoSomething")]
[FaultContract(typeof(EpicFail))]
ResponseObject DoSomething(RequestObject requestObject);
The fault is defined as such:
[DataContract]
public class EpicFail
{
public EpicFail(string action)
{
this.Reason = "Epic Fail";
this.Action = action;
}
[DataMember]
public string Reason
{
get;
set;
}
[DataMember]
public string Action
{
get;
set;
}
}
The code that calls the service looks vaguely like this:
[TestMethod()]
[ExpectedException(typeof(FaultException<EpicFail>))]
public void FaultTest_Fails_Epicly()
{
bool testPassed = false;
try
{
ResponseObject resp = GetServiceClient().DoSomething(req);
}
catch (FaultException<EpicFail>)
{
testPassed = true;
}
Assert.IsTrue(testPassed);
}
I edited the code to show that I am using the ExpectedException attribute and it doesn't seem to be having much effect on keeping the IDE/Debugger from breaking when the exception is thrown in the service.

You can always use ExpectedExceptionAttribute (in NUnit) to make sure this is the exception thrown. MSTest has similar concept as well.
[ExpectedException(typeof(MyException))]
void my_test()
{
// test
}
If you have some Mock verification to do, I would use try/catch block and verify in the catch and then throw the exception.
UPDATE
When you are using ExpectedException attribute, you are not supposed to catch the exception, instead you need to let the NUnit that runs your test to catch it.
If you need to verify special information in the exception then you catch the exception, verify the information and then rethrow:
[ExpectedException(typeof(MyException))]
void my_test()
{
try
{
// call the service
}
catch(MyException ex)
{
Assert.IsTrue(ex.Message.Contains("error code 200"));
throw ex;
}
}

mattv,
Why does this test has to access the service remotely? From what I see your code:
ResponseObject resp = GetServiceClient().DoSomething(req);
Is somehow getting a service client, and not a service instance itself. I'd advise to test the service concrete class directly for unit tests.
However, if you need this scenario, have you tried NOT CATCHING the exception and running the test? Does it give the same result?
And by the way, if you need to catch and rethrow use the following pattern:
try {
//Do something
}
catch(SomeException e) {
//Do something with e
throw
}

Related

Unit test doesn't complete, the method being tested just throws an exception. What am I missing?

I'm currently in the process of working through a Unit Testing in C# course - specifically for NUnit (I'm using NUnit 3.8.1 with NUnit3TestAdapter 3.1.13).
My issue in question, is that when I'm testing for an exception to be thrown, my debugger stops & throws an exception on the method that I'm testing. I'm not sure if I'm mistaken with the behaviour, but I can't see what I've done wrong.
Firstly - I've read up on the documentation & can't see a problem.
I've also looked through various other posts on stack overflow that just don't seem to quite point at the answer, as none of these solutions have worked for me.
Is there some Assert method which can be used for unit test on whether a method throws an exception?
C# Unit Testing - Test method throwing NullReferenceException
Why, when I am testing that a method throws an exception and the method throw an exception, does the test stop?
The class I'm testing is as follows (and was provided from the instructor on the course - they have demonstrated that this works).
using System;
namespace TestNinja.Fundamentals
{
public class ErrorLogger
{
public string LastError { get; set; }
public event EventHandler<Guid> ErrorLogged;
public void Log(string error)
{
if (String.IsNullOrWhiteSpace(error))
throw new ArgumentNullException();
LastError = error;
// Write the log to a storage
// ...
ErrorLogged?.Invoke(this, Guid.NewGuid());
}
}
}
And finally, my test methods -
using NUnit.Framework;
using TestNinja.Fundamentals;
namespace TestNinja.UnitTests
{
[TestFixture]
public class ErrorLoggerTests
{
//private ErrorLogger _errorLogger;
[SetUp]
public void SetUp()
{
//_errorLogger = new ErrorLogger();
}
[Test]
public void Log_WhenCalled_SetTheLastErrorProperty()
{
var logger = new ErrorLogger();
logger.Log("a");
Assert.That(logger.LastError, Is.EqualTo("a"));
}
[Test]
[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
public void Log_InvalidError_ThrowArgumentNullException(string error)
{
var logger = new ErrorLogger();
Assert.That(() => logger.Log(error), Throws.ArgumentNullException);
}
}
}
The test I'm talking about is Log_InvalidError_ThrowArgumentNullException. On each test case the code breaks on the line throw new ArgumentNullException(); in ErrorLogger. I have to close the box & continue running the code.
When I run this test individually, the test runs to completion, however when I run all, that's where the exception is thrown & my testing is stopped.
Originally, my unit testing had the SetUp method uncommented & I was using that private field, however I swapped over to a fresh instance to make sure there weren't any issues with lingering objects.

C# unit testing for a NotFound via a GET

For some reason, I am having troubles making a unit test for the following in C#
[Route("api/Orders/{orderID:int}/Items")]
public OrderItemsDTO Get(int orderID)
{
if (_orderItemsService.Get(orderID).Items.Count() == 0)
{
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, String.Format("Order {0} not found.", orderID)));
}
return _orderItemsService.Get(orderID);
}
I have a unit test running correctly for an Async Add which is what I'm using to Post that I was trying to base my unit test off of with some tweaks I thought it would work, but it doesn't. the following is what I thought should work:
private OrderItemsController _testSubject;
private Mock<IOrderItemsService> _moqOrderItemsService = new Mock<IOrderItemsService>();
[TestInitialize]
public void TestInitialize()
{
_testSubject = new OrderItemsController(_moqOrderItemsService.Object);
}
[TestMethod]
[ExpectedException(typeof(HttpResponseException))]
public async Task ThrowHttpResponseExceptionWhenThereIsAValidationException()
{
_moqOrderItemsService.Setup(ois => ois.Get(It.IsAny<int>()))
.Throws(new ValidationException("test"));
try
{
_testSubject.Get(17);
}
catch(HttpResponseException ex)
{
Assert.IsNotNull(ex.Response);
Assert.AreEqual(HttpStatusCode.NotFound, ex.Response.StatusCode);
throw;
}
}
You set up order item service mock to throw ValidationException when it is called with any id. Then you are expecting controller to throw HttpResponseException which is not true - you will have same exception as you throw from service.
You should setup service to return some object (you didn't provide definition of service interface and types which it returns) with empty Items property:
_moqOrderItemsService.Setup(ois => ois.Get(It.IsAny<int>()))
.Returns(/* some object with empty Items property */);
Now in controller you will go to throwing HttpResponseException path.
Side note: why are you throwing exceptions instead of returning something like Content(HttpStatusCode.NotFound, "Message")? You even can create base controller with method IHttpActionResult NotFound(string message) which will do this for you.
I would suggest not testing the Web API controller, rather test the _orderItemsService and mock out whatever repository you are using in the service. You can assert that the OrderItemsDTO is not null.
Well according to Microsoft testing controllers is best practice: https://learn.microsoft.com/en-us/aspnet/web-api/overview/testing-and-debugging/unit-testing-controllers-in-web-api.

AOP with Autofac and DynamicProxy2 Exception Handling

I'm trying to centrally manage Exception handling for a certain method but I can't seem to get there.
public class ExceptionInterceptor : IInterceptor
{
private readonly Logger _logger;
public ExceptionInterceptor(Logger logger)
{
_logger = logger;
Measure.Configure(new StatsdConfig());
}
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
//if ((Task<System.Threading.Tasks.VoidTaskReturn>) invocation.ReturnValue.Status == "Failed")
//{
// throw new Exception(invocation.ReturnValue.Exception[0]);
//}
}
catch (Exception e)
{
var errorMessage =
String.Format(
"An error occurred while retrieving fund data. Error Message: {0} Inner Exception: {1}",
e.Message, e.InnerException != null ? e.InnerException.Message : "<None>");
_logger.Log(errorMessage);
Measure.Counter("Exception", 1);
Measure.Event("Exception", errorMessage);
throw;
}
}
I'm wiring this up in a module like so:
builder.RegisterType<DataConsumer>().
As<IConsumer<DataRequest>>().
EnableInterfaceInterceptors().
InterceptedBy(typeof(ExceptionInterceptor));
builder.RegisterType<ExceptionInterceptor>().AsSelf();
var loggingInterceptor = new LoggingInterceptor(Logger);
builder.Register(c => loggingInterceptor);
However when I throw an exception in the method invocation this doesn't bubble up to the interceptor as an exception thrown, so it never enters the catch block.
Is there any way to catch the intercepted method's exception in the interceptor?
I also can't access the invocation.ReturnValue.Status for some reason and as such can't test whether there was a thrown exception in order to re-throw.
Can anyone shed some light into what I might nor be doing right here?
Ta
I'm having a difficult time reproducing your issue due to a bit of incomplete information. For example, you noted that the IConsumer<T> interface is a MassTransit interface, but the interface in MassTransit isn't generic. It also specifically mentions that the interface is supposed to be a marker just for IoC containers, which may have some implications on your wire-up.
First, let's post a working exception handling example. To be self-contained, I'll create an IWorker<T> interface in place of IConsumer<T> and a simple implementation:
public interface IWorker<T>
{
bool DoWork(T message);
}
public class StringWorker : IWorker<string>
{
public bool DoWork(string message)
{
throw new DivideByZeroException();
}
}
Now I'll create a simple exception logger that just pipes info to the console.
public class ExceptionLogger : IInterceptor
{
private readonly TextWriter _output;
public ExceptionLogger(TextWriter output)
{
_output = output;
}
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch(Exception ex)
{
_output.WriteLine("Logged Exception: {0}", ex.Message);
throw;
}
}
}
I can then wire it up and see it in action like this:
var builder = new ContainerBuilder();
builder.RegisterInstance(Console.Out).As<TextWriter>();
builder.RegisterType<ExceptionLogger>();
builder.RegisterType<StringWorker>()
.As<IWorker<string>>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(ExceptionLogger));
var container = builder.Build();
var worker = container.Resolve<IWorker<string>>();
worker.DoWork("Test!");
When I run this, I see on the console just before the program dies (with the unhandled exception - note my handler didn't swallow it, just logged it):
Logged Exception: Attempted to divide by zero.
So it's working.
I think there's more in your environment that may be causing trouble here. It could be something you think is unrelated but is actually important.
General things to investigate:
Temporarily update your DataConsumer to throw an exception immediately inside one of the interface methods. After building your container, resolve a, IConsumer<DataRequest> and call that interface method. Does it get logged?
Look at the places that you're expecting to see logging occur. Are you resolving and working with IConsumer<DataRequest> or something else? It's wrapping the interface methods, not the object type, so not all methods are covered.
Set a breakpoint in the interceptor and see if any invocation at all is passing through it. It won't catch exceptions if it's not being hit. :)
Check to see if there's any other exception handling policies or code in action. For example, some folks use the Enterprise Library exception handling block to deal with exceptions and that may be interfering with your work here.
I've not used MassTransit, but check to see if there's any other object proxying going on. (Doubtful, but I know I've run into this with products like Glimpse, so you end up with proxies wrapped around proxies, which becomes challenging.)
Is the exception actually happening in the place you think it is? It may be happening and getting handled somewhere that isn't wrapped with the proxy.
Basically, reduce the working pieces to the smallest set possible until you can see it working, then slowly expand until you find the place it breaks down. I don't know if any of these apply to your situation, but these are the things I'd start looking at if I was troubleshooting.
But... exception handling in an AOP fashion using interceptors does work, so it's something else going on that's causing the challenge.
It seems that it isn't possible for the exception thrown in the target proxy to be pushed up to the interceptor, and as such what I was trying to do didn't work. I ended up handling the exceptions at the class they occur.
Disappointed I didn't manage to get this to work the way I was intending to.

How to pass test outcome to different method in c# unit/integration tests?

I have bunch of unit/integration tests which creates a report after all the tests are run. At the moment i am passing in a hard coded response to the method that creates report.
How can i get the outcome of the test method? so that i can pass in this outcome as the response.
See how the test output shows us the Test Outcome i want to retrive that inside the test method. I know its possible. I have been able to retrieve the test name but couldn't get the outcome. Any help really appreciated.
Note: i am using normal MSTests
When a test fails the Test Method is automatically aborted. You can use the CurrentTestOutcome property in the TestCleanup method. If you want to take the StackTrace you have to put all the method's code inside a try/catch block.
[TestClass]
public class TestClass
{
[TestCleanup]
public void TestCleanup()
{
// here you have access to the CurrentTestOutcome bot not on stacktrace
if (TestContext.CurrentTestOutcome == UnitTestOutcome.Failed)
{
// do something
}
}
[TestMethod]
public void TestMethod()
{
try
{
// Your test code here
}
catch (Exception exception)
{
// here you have access to the StackTrace
TestContext.WriteLine(exception.StackTrace);
// You can also add it to the TestContext and have access to it from TestCleanup
TestContext.Properties.Add("StackTrace", exception.StackTrace);
// Or...
TestContext.Properties.Add("Exception", exception);
throw;
}
}
}
In order to get test outcome you can use TestContext.CurrentTestOutcome property. You will get there Passed, Failed, Unknown values. As far as stack trace is concerned I think you should use StackTrace class.

log all handled exception using log4net + AutoFac interceptor

I'm using Log4Netto log my application. currently I want to log every methods enter in my app (for testing purpose). Therefor I'm using AutoFac interception capabilities, somethong like this:
builder.Register(c=> new MyClass()).As<IMyInterface>().EnableInterfaceInterceptors().InterceptedBy(typeof(LoggerClass));
builder.Build();
and my LoggerClass looks something like this:
public class LoggerClass : StandartInterceptor
{
ILog _log = LogManager.GetLogger(typeof(LoggerClass));
override void PreProceed(IInvocation invovation)
{
_log.Info(string.Format("entering method: {0}",invocation.Method.Name);
}
}
for now this implementation will print message for all method invocation (the interceptor catches all methods entries).
Question
I would like to use this interception mechanism to log every handled Exception.
For example instead of coding this:
catch (myException ex)
{
_log.Error(string.Format("catches exception {0}", ex.Message));
}
I'll have extra method in my LoggerClass that will wrap the catch statement and inject to it log message.
Is there any way to do it using Log4Net? since basically the interceptor work around the method, and I need it to work inside method.
On your caught exceptions, you will never enter into the catch block of your interceptor.
Therefore, in your method when you catch an exception, you can handle the caught exception in an additional intercepted method that will get logged appropriately. This will inflate your codebase a bit, but you will end up getting the information you want without sacrificing your architecture.
public void InterceptedMethod()
{
try
{
//Some code that fails.
}
catch
{
HandleException();
}
}
//Intercept this method also
public void HandleException()
{
}

Categories

Resources