The title is self explanatory but I'll elaborate.
I'm using FakeItEasy framework where I have the option to check the number of times a method have been invoked.
A.CallTo(() => foo.Bar()).MustHaveHappened();
But by doing this I'm testing the internal behavior of my code. I'm not testing a returned value or a state change which is what a good test should do.
so my question is this: is it a good practice to test the number of times a method have been called?
You should care about the number of times a dependency was invoked in many cases.
For example, suppose your have a service that inserts some data into some database by invoking a web service.
public interface IDataInserter
{
void Insert(Data[] data);
}
And assume that in some cases you need to insert some 10000 items. But the web service cannot handle such volume of data in a single call. So you decide to create a decorator that will split the data into multiple chunks and send each chunk in a single request.
public class SplittingDecorator : IDataInserter
{
private readonly IDataInserter m_DataInserter;
public SplittingDecorator(IDataInserter data_inserter)
{
m_DataInserter = data_inserter;
}
public void Insert(Data[] data)
{
var chunks =
data
.Select((d, i) => new {d, i})
.GroupBy(x => x.i/50)
.Select(x => x.Select(y => y.d).ToArray())
.ToList();
foreach (var chunk in chunks)
{
m_DataInserter.Insert(chunk);
}
}
}
When you want to test the SplittingDecorator class, you will create a mock for the data_inserter constructor argument.
In such test, you need to assert that the mocked IDataInserter was invoked some X times when you invoke SplittingDecorator.Insert with a data of size Y.
For example, if the data size (length of the data array) is 160 items, you want to check that the mock was invoked 4 times.
Related
I have an Autofac DI Container defined as follows:
public class Bootstrapper
{
public IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<ItemViewModel>().AsSelf();
builder.RegisterType<EventAggregator>()
.As<IEventAggregator>()
.SingleInstance();
}
}
I have a Unit Test defined to test whether a deletion removes the deleted item from the collection:
[Fact]
public void Should_remove_item_from_collection_when_item_is_deleted()
{
const int deletedId = 42;
// adds three items to the collection
_openItemEditViewEvent.Publish(deletedId);
_openItemEditViewEvent.Publish(8);
_openItemEditViewEvent.Publish(9);
// I've tried this:
_eventAggregatorMock.Object.GetEvent<ItemDeletedEvent>().Publish(42);
// and alternatively, this (not at the same time):
_itemDeletedEventMock.Object.Publish(42);
Assert.Equal(2,_vm.ItemEditViewModels.Count); // always fails
Assert.False(_vm.ItemEditViewModels
.Select(vm => vm.Item.Id).Contains(42), "Wrong item deleted");
}
The constructor of the Unit Test initializes and assigns the EventAggregator to the view model:
_eventAggregatorMock = new Mock<IEventAggregator>();
_itemDeletedEventMock = new Mock<ItemDeletedEvent>();
_eventAggregatorMock.Setup(ea => ea.GetEvent<ItemDeletedEvent>())
.Returns(_itemDeletedEventMock.Object);
_vm = new ItemViewModel(_eventAggregatorMock.Object, */ ... /*);
In my actual view model, I Subscribe to the event:
public ItemViewModel(IEventAggregator ea, /* ... */)
{
_eventAggregator.GetEvent<ItemDeletedEvent>()
.Subscribe(OnItemDeleted, true);
}
And we never hit a breakpoint here:
public void OnItemDeleted()
{
// never happens
}
For the life of me, I can't figure out what I'm doing wrong - I'm overlooking something... do I have to Setup the event's Publish event in the Mock? Should I be using a real ItemDeletedEvent instance instead of a Mock? Any help would be greatly appreciated.
=> Hi Scott,
there are 2 ViewModel-scenarios you want to test when using an EventAggregator:
You want to test that your ViewModel is publishing an event
You want to test that your ViewModel does something when an event was published. So the ViewModel has to subscribe to that Event to do something
(Note: The following lines are true for PRISM's EventAggregator, which is the one you're using I guess. For other EventAggregators it could be different)
For the first scenario, you have to create a mock for the event. Then you can verify on that mock-instance that the Publish-method of the Event has been called.
For the second scenario, which is the scenario you have in your question, you have to use the real event in your test. Why?
When you call the Publish-method on a event-mock, that Publish method won't call the subscribers to that Event, as there's no logic behind the Subscribe-method. For sure you could setup both methods and implement that publish/subscribe-logic in your mock. But there's no reason to do so, just use the real Event
When you use the real event, the Publish-method will call all the subscribers. And this is exactly What you need in your test.
It should look like this:
_itemDeletedEvent = new ItemDeletedEvent();
_eventAggregatorMock.Setup(ea => ea.GetEvent<ItemDeletedEvent>())
.Returns(_itemDeletedEvent);
Now your ViewModel will get this itemDeletedEvent-instance from the EventAggregator. In your test you call the Publish-method on this itemDeletedEvent-instance and it will work.
More about this is explained in my Course on Pluralsight about WPF and Test Driven Development: http://www.pluralsight.com/courses/wpf-mvvm-test-driven-development-viewmodels
Thomas
http://www.thomasclaudiushuber.com
I'm converting a webtest that loops 100 times (fires the request and validates the response 100 times) to NUnit. It seems that the [Repeat] attribute only works for [Test], not [TestCase] or any other decoration/attribute. What is the cleanest way to do this? I want to fire that one test case with those parameters 100 times, and I'd like to do it without adding a loopCount parameter to my test case and nesting my act and assert sections in a for loop.
The below code only runs once.
[TestCase("arg1", "arg2"), Repeat(100)]
public void testing(string arg1, string arg2)
{
//Arrange
//Act
var response = RequestSender.SendGetRequest();
//Assert
AssertStuff(arg1, arg2);
}
From the online NUnit documentation for Repeat, it would appear that this behaviour is deliberate.
Notes:
It is not currently possible to use RepeatAttribute on a TestFixture or any other type of test suite. Only single tests may be repeated.
Since a parameterized test method represents a suite, RepeatAttribute is ignored when it appears on such a method.
With the assumption that TestCase is obviously regarded as a parameterized test. The loop looks inevitable, without some additional customization?
What you could do instead is use use a test case source and feed it an enumerable of 100 repeated items:
private static readonly IEnumerable<Tuple<string, string>> _oneHundredCases =
Enumerable.Range(0, 100)
.Select(_ => Tuple.Create("arg1", "arg2"));
[TestCaseSource(nameof(_oneHundredCases))]
public void testing(Tuple<string, string> theArgs)
{
...
AssertStuff(theArgs.Item1, theArgs.Item2);
}
But for the same price, you may as well vary the arguments a bit?, e.g.
_oneHundredCases =
Enumerable.Range(0, 100)
.Select(n => Tuple.Create(n.ToString(), $"arg{n}"));
I want to create a unit test that validates a Logger.Write command is executed with the correct message in one of my MVC controllers.
I can mock the Listener that the Logger writes to, but I do not know how to reach the message that is stored. For example,
var mockListener = new Mock<MyTraceListener>();
// the .Write method is void so I can't use .Returns() on my mock
mockListener.Setup(listener => listener.Write(It.IsAny<string>()))
MyController controller = new MyController();
MyController.Index();
// and then the Index method calls the following Logger.Write() to the category that writes to MyTraceListener:
Logger.Write("test message", "MyCategory");
This write command to the logger does not return the input string or store it into a parameter for me to validate with an Assertion statement. Can I use one of the Moq verifies or setups or the .when (whatever this is) functions to get the message that is logged, or at least check that it executed?
Preferably, I want to store the log entry into a variable in my unit test so I can assert this:
Assert.AreEqual(loggedMessage, "test message");
If anyone knows of a strategy to do this I would greatly appreciate it.
Assuming you're using Entlib 5.0, there's already a mock point for you. Instead of using Logger.Write directly, instead inject an instance of LogWriter into your controller. You can then mock out the LogWriter object in your tests.
You want to use the Callback as a way to get the input from your Write method back to your unit test.
Because Loggers is static, you'll have to wrap the calls to those static methods in order to use Moq in your tests. The sample class below should be all you need to do to pull that off. You'll also have to update your code to use the wrapper, that might be painful.
Here is a sample test and class structure to achieve this.
public class Logger
{
public virtual void Write( string message, string category )
{
Loggers.Write( message, category );
}
}
[TestMethod]
public void SampleTest()
{
string input = string.Empty;
var mockLogger = new Mock<Logger>();
mockLogger.Setup( l => l.Write( It.IsAny<string>(), It.IsAny<string>() ) ).Callback( ( string message, string category ) => input = message );
mockLogger.Object.Write( "test", "category" );
Assert.AreEqual( "test", input );
}
Please note I'm using Moq version 4.0.10827.0.
I hope this helps!
I have a method called ProcessPayment() that I'm developing via BDD and mspec. I need help with a new challenge. My user story says:
Given a payment processing context,
When payment is processed with valid payment information,
Then it should return a successful gateway response code.
To set up the context, I am stubbing my gateway service using Moq.
_mockGatewayService = Mock<IGatewayService>();
_mockGatewayService.Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>()).Returns(100);
Here's the spec:
public class when_payment_is_processed_with_valid_information {
static WebService _webService;
static int _responseCode;
static Mock<IGatewayService> _mockGatewayService;
static PaymentProcessingRequest _paymentProcessingRequest;
Establish a_payment_processing_context = () => {
_mockGatewayService = Mock<IGatewayService>();
_mockGatewayService
.Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>())
.Returns(100);
_webService = new WebService(_mockGatewayService.Object);
_paymentProcessingRequest = new PaymentProcessingRequest();
};
Because payment_is_processed_with_valid_payment_information = () =>
_responseCode = _webService.ProcessPayment(_paymentProcessingRequest);
It should_return_a_successful_gateway_response_code = () =>
_responseCode.ShouldEqual(100);
It should_hit_the_gateway_to_process_the_payment = () =>
_mockGatewayService.Verify(x => x.Process(Moq.It.IsAny<PaymentInfo>());
}
The method should take a `PaymentProcessingRequest' object (not domain obj), map that obj to a domain obj, and pass the domain obj to the stubbed method on the gateway service. The response from the gateway service is what gets returned by the method. However, because of the way I am stubbing my gateway service method, it doesn't care what gets passed in to it. As a result, it seems I have no way to test whether or not the method maps the request object to the domain object properly.
When can I do here and still adhere to BDD?
To check that the object sent to your IGatewayService is correct, you can use a callback to set a reference to the domain object. You can then write your assertions on properties of that object.
Example:
_mockGatewayService
.Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>())
.Callback<PaymentInfo>(paymentInfo => _paymentInfo = paymentInfo);
So from what I understand,
You want to test the mapping logic in the WebService.ProcessPayment method ; there is a mapping of an input parameter A to an object B, which is used as an input to a GateWayService collaborator.
It should_hit_the_gateway_to_process_the_payment = () =>
_mockGatewayService.Verify(
x => x.Process( Moq.It.Is<PaymentInfo>( info => CheckPaymentInfo(info) ));
Use the Moq It.Is constraint which takes in a Predicate (a test for the argument to satisfy). Implement CheckPaymentInfo to assert against the expected PaymentInfo.
e.g. to check if Add is Passed an even number as an argument,
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true);
Is it possible to mock a stub/mock's object member call without having to define that as a stub, and also set the return value as all seperate verbose lines?
Example:
[TestMethod]
public void AssignedPermissions_AssociateExists_ReturnsEdit_Rhino()
{
//Arrange
var fakeConfiguration = MockRepository.GenerateStub<IDomainControllerConfiguration>();
var fakeAssociateRepository = MockRepository.GenerateStub<IAssociateRepository>();
fakeConfiguration.Stub(x => x.AssociateRepository).Return(fakeAssociateRepository);
fakeAssociateRepository.Stub(x=>x.GetAssociatesByRole(null,false,null)).IgnoreArguments()
.Return(new IAssociate[]{MockRepository.GenerateStub<IAssociate>()});
var domain = new DomainController(fakeConfiguration);
const AssignedPermission expected = AssignedPermission.Edit;
//Act
AssignedPermission actual = domain.AssignedPermissions();
//Assert
Assert.AreEqual(expected, actual);
}
Are all those temporary variables necessary just to stub out nested method calls?
I've never used the functionality, so I'm not 100% certain that this will work, but theoretically Rhino mocks supports "recursive mocking", which should allow you to at least cut out the fakeAssociateRepository by doing something like this:
var fakeConfiguration = MockRepository.GenerateStub<IDomainControllerConfiguration>();
fakeConfiguration.Stub(x => x.AssociateRepository.GetAssociatesByRole(null,false,null))
.IgnoreArguments()
.Return(new IAssociate[]{MockRepository.GenerateStub<IAssociate>()});
var domain = new DomainController(fakeConfiguration);
(note: code not tested, or even compiled)
Just wanted to share my input on this, since I just spent the last few hours wrestling with it. The answer posted above by Alconja absolutely works, but if you plan to use it for "AssertWasCalled" type of assertion, it does not assert the way I expected it to. It seems that the AssertWasCalled methods tried to assert the "get accessor" associated with the "nested" object.
For instance, if you wanted to do this:
fakeconfiguration.AssertWasCalled(x => x.AssociateRepository.GetAssociatesByRole(null, false, null));
You would get an exception such as
System.InvalidOperationException : Previous method 'IDomainControllerConfiguration.get_AssociateRepository();' requires a return value or an exception to throw.
Because the AssertWasCalled is asserting the get-accessor of the AssociateRepository property, rather than the GetAssociatesByRole() method. In the end, for my case I had to use the OP's methodology of creating mutliple stubs.