How to debug theories in xunit tests - c#

I have big amount of similar tests which I implement as a theory using MemberData attribute. How can I navigate to each fallen test case and debug it?
Here an example:
public const int A = 2;
public const int B = 3;
public const int C = 2;
public static IEnumerable<object[]> GetTestCases
{
get
{
// 1st test case
yield return new object[]
{
A, B, 4
};
// 2nd test case
yield return new object[]
{
A, C, 4
};
}
}
[Theory]
[MemberData("GetTestCases")]
public void TestMethod1(int operand1, int operand2, int expected)
{
// Q: How can I debug only test case, which is failed?
//...and break execution before exception will be raised
var actual = operand1 + operand2;
Assert.Equal(actual, expected);
}

Well, you can set conditional breakpoint in TestMethod1 and try to find fallen test case. But in many cases it is not so comfortable.
One trick can be helpful here:
public const int A = 2;
public const int B = 3;
public const int C = 2;
public static IEnumerable<object[]> GetTestCases
{
get
{
// 1st test case
// This line will be in stack trace if this test will failed
// So you can navigate from Test Explorer directly from StackTrace.
// Also, you can debug only this test case, by setting a break point in lambda body - 'l()'
Action<Action> runLambda = l => l();
yield return new object[]
{
A, B, 4,
runLambda
};
// 2nd test case
runLambda = l => l();
yield return new object[]
{
A, C, 4,
runLambda
};
// ...other 100500 test cases...
}
}
[Theory]
[MemberData("GetTestCases")]
public void TestMethod1(int operand1, int operand2, int expected, Action<Action> runLambda)
{
// pass whole assertions in a callback
runLambda(() =>
{
var actual = operand1 + operand2;
Assert.Equal(actual, expected);
});
}
Idea is to put target logic and assertions into callback and call it through a special similar lambdas which are injected in each test case. Every of that lambdas will be passed as argument and called in test method, so it will be present in stack trace. And when some test case will fall, you can easily navigate to it through StackTrace by clicking on corresponding line (in this example it will looks like 'at UnitTestProject1.ExampleTests2.<>c.b__4_0(Action l)')
Also, you can set breakpoint inside lambda of that test case, which you want to debug and see what is happen with data.

Related

How to get result of method called inside of a mocked class

There is a way to get the result returned from a method called into a mocked object?
For example, if I have the following classes and an interface:
DoSomethingClass.cs
public class DoSomethingClass
{
IInternalClass _intClass;
public DoSomethingClass(IInternalClass intClass)
{
_intClass = intClass;
}
void DoSomething(int number)
{
// do some transformation to the number, e.g.
var transformedNumber = number * (number - 1);
var x = _intClass.IsEven(transformedNumber);
// do something else
}
}
InternalClass.cs
public interface IInternalClass
{
bool IsEven(int number);
}
public class InternalClass: IInternalClass
{
public InternalClass();
public bool IsEven(int number)
{
return number % 2 == 0;
}
}
And a test class:
Tests.cs
public class Tests
{
[Fact]
public async Task test_something()
{
//PREPARE
var request = 10
var internalMock = new Mock<IInternalClass>();
var classToTest = new DoSomethingClass(internalMock.Object);
// ACT
await classToTest.DoSomething(request);
//ASSERT
//Here I want to check if the method IsEven of the internal class return the right result
}
}
}
What I want to assert is the return value of the method IsEven of the InternalClass called inside the main method DoSomething, there is no way that I can know the transformedNumber calculated inside this method and passed to IsEven.
NOTE: I use the Moq library to mock object.
Excuse me for the stupid example above, but I don't have any simple real code to show here, however I hope this can be sufficient to understand the question.
I am assuming that you want to verify that your IsEven method is called on the mocked IInternalClass?
If that is the case then you can use the Verify method on the mock as follows:
[Fact]
public void DoSomething_Verify()
{
var request = 10;
var internalMock = new Mock<IInternalClass>();
var classToTest = new DoSomethingClass(internalMock.Object);
classToTest.DoSomething(request);
//Verify that the mock is invoked with the expected value, the expected number of times
internalMock.Verify(v => v.IsEven(90), Times.Once);
//There are lots of other options for Times, e.g. it is never called with an unexpected value maybe.
internalMock.Verify(v => v.IsEven(91), Times.Never);
}
Also to call the DoSomething method with await you would need to change the method signature as follows:
public async Task DoSomethingAsync(int number)
{
// do some transformation to the number, e.g.
var transformedNumber = number * (number - 1);
var x = _intClass.IsEven(transformedNumber);
// do something else
}
Then you can create a unit test like this:
[Fact]
public async void DoSomething_VerifyAsync()
{
var request = 10;
var internalMock = new Mock<IInternalClass>();
var classToTest = new DoSomethingClass(internalMock.Object);
//To call the DoSomething method with await the method needs the async Task and a good convention is to append Async to the name
await classToTest.DoSomethingAsync(request);
//Another slightly more generic option is to verify that the mock was called with and int exactly n Times
internalMock.Verify(v => v.IsEven(It.IsAny<int>()), Times.Exactly(1));
}

How to test function that has objects as parameters in XUnit?

I have a simple function that takes Client and Supplier data and then calculates tax based on where they live and other information:
static int CountTax(Supplier tiek, Client kl, bool same_country)
{
if ( !tiek.is_PVM_payer)
return 0;
else
{
if (!kl.EU)
return 0;
else
{
if (same_country)
return kl.x;
else
{
if (kl.is_PVM_payer)
return 0;
else
return kl.x;
}
}
}
}
Now I am required to write tests for this function. It is the first time I am encountering tests. I am using XUnit testing. And my test class looks like this:
using System;
using Xunit;
namespace CountTax_tests
{
public class UnitTest1
{
[Theory]
[InlineData(typeof(Client))]
public void Tax_is_0()
{
// arrange
int expectedVal = 0;
int actualVal;
/// act
actualVal = MyProgram.MyprogramCode.CountTax(supplier, client, same_country);
// assert
Assert.Equal(expectedVal, actualVal);
}
[Fact]
public void PVM_is_x()
{
int expectedVal = x;
int actualVal;
actualVal = MyProgram.MyprogramCode.CountTax(supplier, client, same_country);
Assert.Equal(expectedVal, actualVal);
}
}
}
But how do I pass my Client and Supplier parameters to that test? Please help me and lead on a path because I am completely new and nothing is clear to me even after many tutorials...
Maybe I have to use [Theory]? Or maybe [Fact]? Or maybe it is impossible to pass classes as parameters?
Also, [InlineData(typeof(Client))] is being underlined in red and is not working.

Performing actions with method returned values

I have class: class_getanswer and class: class_performaction
in class_getanswer i have method:
class class_getanswer
{
static public int capacity()
{
Random block = new Random();
int beta = block.Next(1, 8);
return beta;
}
}
in class with method Main i want that answer to be in function if:
class class_performaction
{
static void Main()
{
int value = 5;
if(class_getanswer.capacity() < value)
{
Console.WriteLine("bla bla bla");
}
}
}
but i get that "if" doesn't exist in this context, why?
There is screenshot of kinda full programm but in different language (lithuanian): https://www.dropbox.com/s/jggwgt738vltawx/functionswt.PNG?dl=0
Please check the case of, if statement. I believe you wrote If(with a capital 'I'), change it to small case 'i'.

Non static fields in unit test don't update on second and further test run

I encountered this weird situation and do not see explanation.
[TestClass]
public class DbHelpersTests
{
int addCalls;
int commitCalls;
int updateCalls;
[TestInitialize]
public void SetUp()
{
StubICustomerRepository stubRepo = new StubICustomerRepository()
{
AddCustomerModelBoolean = (model, autoSave) =>
{
addCalls++;
return true;
},
Commit = () =>
{
commitCalls++;
return true;
}
};
StubIOrderRepository orderRepo = new StubIOrderRepository()
{
AddOrderBoolean = (order, save) =>
{
addCalls++;
return true;
},
UpdateOrderBoolean = (order, save) =>
{
updateCalls++;
return true;
}
};
...
}
[TestCleanup]
public void CleanUp()
{
addCalls = 0;
commitCalls = 0;
updateCalls = 0;
}
[TestMethod]
public void AddMultipleCustomers()
{
...
List<Customer> data = PrepareData(10);
// commit after each 2 customers
DbHelpers.InsertAllCustomers(data, 2);
Assert.AreEqual(10, addCalls);
Assert.AreEqual(5, commitCalls);
}
[TestMethod]
public void AddSingleOrder()
{
...
DbHelpers.InsertOrder(new Order());
Assert.AreEqual(1, addCalls);
}
[TestMethod]
public void UpdateSingleOrder()
{
...
DbHelpers.UpdateOrder(new Order());
Assert.AreEqual(1, updateCalls);
}
}
When I run my tests, the first one AddMultipleCustomers passes and later two don't. They fail because addCalls and updateCalls fields are both 0.
When I run only AddSingleOrder test it passes. Same with UpdateSingleOrder.
Why, when running all tests, in second and following test runs, fields addCalls and updateCalls are not updated anymore?
When I changed the declaration of fields to static int addCalls;, all tests passed. Why?
Have you stepped through it in the debugger? I figure DbHelpers is static methods. Without having more of the code... since TestInitialized is called every test, new stubs are generated, but maybe the static methods are still referencing the first stubs and the first instances of the class variables (they get recreated after each run). So the second and third runs are referencing new versions of the fields that are set to 0 and the Stubs are incrementing the first version. You should be able to use the debugger to check (just remove the explicit set to 0 in the cleanup method).

Rhinomocks - Mocking delegates

public interface IServiceInvoker
{
R InvokeService<T, R>(Func<T, R> invokeHandler) where T : class;
}
public class MediaController : Controller
{
private IServiceInvoker _serviceInvoker;
public MediaController(IServiceInvoker serviceInvoker)
{
_serviceInvoker = serviceInvoker;
}
public JsonResult GetAllMedia()
{
var media = _serviceInvoker.InvokeService<IMediaService, List<MediaBase>>(proxy => proxy.GetAllMediaInJson());
JsonResult jsonResult = new JsonResult();
jsonResult.Data = media;
jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return jsonResult;
}
[TestClass]
public class MediaControllerTests
{
[TestMethod]
public void GetAllMedia()
{
JsonResult data;
var serviceInvoker = MockRepository.GenerateStub<IServiceInvoker>();
var media = CreateSeveralMedia();
serviceInvoker.Stub(c => c.InvokeService<IMediaService, List<MediaBase>>(p => p.GetAllMediaInJson())).Return(media);
data = new MediaController(serviceInvoker).GetAllMedia();
serviceInvoker.VerifyAllExpectations();
Assert.IsNotNull(data);
}
}
I am stubbing the service and returning a collection. When I run this test, media is null. Any idea, how can I set expectations on this mock ?
Just found a solution. It seems to be a little ugly, but it is the first iteration only probably more elegant version will appear soon. The idea is to create another stub and match Func<> against it:
I will provide code for my use case:
[Theory]
[InlineData(342, 31129, 3456)]
public void should_call_service_invoker_and_return_result(int number1, int number2, int expected)
{
var calculator = MockRepository.GenerateStub<ICalculator>();
calculator.Stub(_ => _.Add(number1, number2)).Return(expected);
var serviceInvoker = MockRepository.GenerateStub<ServiceInvoker<ICalculator>>();
serviceInvoker
.Stub(_ => _.Invoke(Arg<Func<ICalculator, int>>.Matches(d => d(calculator) == calculator.Add(number1, number2))))
.Return(expected);
var serviceConsumer = new ServiceConsumer(serviceInvoker);
var actual = serviceConsumer.GetAddResultFor(number1, number2);
Assert.Equal(expected, actual);
}
xUnit + extensions is used as testing framework. Please ignore Theory and InlineData stuff -- it is just another way to get rid of unnecessary test setup.
Here is the code of SUT:
public class ServiceConsumer
{
private readonly ServiceInvoker<ICalculator> serviceInvoker;
public ServiceConsumer(ServiceInvoker<ICalculator> serviceInvoker)
{
this.serviceInvoker = serviceInvoker;
}
public int GetAddResultFor(int number1, int number2)
{
return serviceInvoker.Invoke(_ => _.Add(number1, number2));
}
}
public class ServiceInvoker<T>
{
public virtual R Invoke<R>(Func<T, R> func)
{
throw new NotImplementedException();
}
}
public interface ICalculator
{
int Add(int number1, int number2);
}
Hope this will be helpful. Any suggestions of how to add more beauty are welcome :)
The lambda in your unit test compiles into a class-level method (a method inside your unit test). Inside your controller, a different lambda compiles into a class-level method (inside the controller). The stub set up in your unit test doesn't match the stub being executed in your controller, so Rhino Mocks returns a default (null). More here: http://groups.google.com/group/rhinomocks/browse_frm/thread/a33b165c16fc48ee?tvc=1

Categories

Resources