Unit Testing Order of Operations - c#

Suppose we want to make steaks.
Public class Restaurant{
public void MakeSteak(Steak rawSteak) {
this.KitchenServices.AddSeasoning(rawSteak);
this.KitchenServices.Grill(rawSteak);
}
}
In the unit tests, I could make sure that given a raw steak, we both season it and grill it:
public void MakeSteakTest() {
var rawSteak = new Steak();
this.restaurant.MakeSteak(rawSteak);
this.KitchenServices.Verify(x => x.AddSeasoning(rawSteak) , Times.Once);
this.KitchenServices.Verify(x => x.Grill(rawSteak) , Times.Once);
}
My question is that should we have a test to make sure that the steak is not seasoned after it's grilled? If yes, How?

Generally you should test results, not implementation in a unit test. What happens in your system if MakeSteak were changed so that the operations were in a different order? Is that something that is observable? Since your only intput is a Steak object, is there some sort of validation that fails if Grill is called before AddSeasoning? That is what you should be testing.

One way would be to represent each operation as a command object which operates on the steak e.g.
interface ISteakOp {
void DoTo(Steak s);
}
class AddSeasoningOp : ISteakOp { ... }
class GrillOp : ISteakOp { ... }
then return a sequence of operations:
public List<ISteakOp> MakeSteakOps() {
return new List<ISteakOp> {
new AddSeasoningOp(),
new GrillOp()
};
}
then your test can assert that any grill op occurs before any seasoning:
var ops = MakeSteakOps();
var grillIndex = ops.IndexOf(o => o is GrillOp);
if (grillIndex != -1) {
var seasonIndex = ops.IndexOf(o = o is AddSeasoningOp);
Assert.That(seasonIndex == -1 || seasonIndex < grillIndex);
}

My question is that should we have a test to make sure that the steak is not seasoned after it's grilled?
First: Does it have an effect on behavior that is visible to the End User/Stakeholder, and do they care?
If yes, How?
Then:
How is it that the is able to detect that effect on behavior? Use that same method in your test.
What's the behavior that the user is expecting? Use that expectation in your test.
This might sound "too straightforward"/"dismissively simple", but I'm totally serious. That is the definition of proper behavioral testing.

Related

Unit Testing a Basic c# application with repository

I have a basic .NET application that I am being asked to write a unit test for, but unit tests have always confused me.
This application has two repositories (FoodRepository and DrinkRepository) that return data from a hardcoded list.
Here's the Program.cs:
public static void Main(string[] args)
{
var foodSvc = new FoodService();
var foodId = 12;
var grade = 98.2d;
foodSvc.UpdateFoodGrade(foodId, grade);
}
which calls:
public void UpdateFoodGrade(int foodId, double grade)
{
var foodRepo = new FoodRepository();
var food = foodRepo.GetFood(foodId);
food.Grade = grade;
if (!food.IsPassed)
{
var drinkRepository = new DrinkRepository();
var drink = drinkRepository.GetDrink(foodId);
if (grade >= drink.MinimumPassingGrade)
{
food.IsPassed = true;
}
else
{
food.IsPassed = false;
}
}
}
My question is, what unit test(s) typically would someone do here for this? And, can I get some examples?
Been googling and grinding on this, but the concept continues to escape me.
I've historically used full integration tests in test environments, and not really done unit tests.
If anyone needs more of the code to help with this please let me know. I'm super stuck.
Thanks
UPDATE:
I've gotten a lot further thanks to below, but I am still stuck on the rest of the test. Here's what my updated service looks like:
public class FoodService
{
private readonly FoodRepository _foodRepo;
private readonly DrinkRepository _drinkRepository;
public FoodService(FoodRepository foodRepo, DrinkRepository drinkRepository)
{
_foodRepo = foodRepo;
_drinkRepository = drinkRepository;
}
public void UpdateFoodGrade(int foodId, double grade)
{
var food = _foodRepo.GetFood(foodId);
food.Grade = grade;
if (!food.IsPassed)
{
var drink = _drinkRepository.GetDrink(foodId);
if (grade >= drink.MinimumPassingGrade)
{
food.IsPassed = true;
}
else
{
food.IsPassed = false;
}
}
}
}
Updated Main:
public class Program
{
public static void Main(string[] args)
{
var foodRepository = new FoodRepository();
var drinkRepository = new DrinkRepository();
var foodSvc = new FoodService(foodRepository, drinkRepository);
var foodId = 12;
var grade = 98.2d;
foodSvc.UpdateFoodGrade(foodId, grade);
}
}
Test So far (I have no idea what to do next)
[TestMethod]
public void UpdateFoodGrade_Test()
{
//Arrange
var foodId = 12;
var grade = 98.2d;
var expected = true;
var food = new Food() { FoodId = foodId };
var drink = new Drink() { DrinkId = foodId };
var foodRepositoryMock = new Mock<FoodRepository>();
foodRepositoryMock.Setup(m => m.GetFood(foodId)).Returns(food).Verifiable();
var drinkRepositoryMock = new Mock<DrinkRepository>();
drinkRepositoryMock.Setup(m => m.GetDrink(foodId)).Returns(drink).Verifiable();
var foodService = new FoodService(foodRepositoryMock.Object, drinkRepositoryMock.Object);
//Act
var actual = foodService.UpdateFoodGrade(foodId, grade);
//Assert
foodRepositoryMock.Verify();
drinkRepositoryMock.Verify();
Assert.AreEqual(expected, actual);
}
}
EDIT 2:
I went ahead and refactored in the interfaces, etc. Here's how it shook out:
[TestMethod]
public void UpdateLessonGrade_IsPassingGrade()
{
//Arrange
var lessonId = 12;
var lesson = new Lesson() { LessonId = lessonId };
var module = new Module() { ModuleId = lessonId };
var lessonRepositoryMock = new Mock<ILessonRepository>();
lessonRepositoryMock.Setup(x => x.GetLesson(lessonId)).Returns(lesson);
var moduleRepositoryMock = new Mock<IModuleRepository>();
moduleRepositoryMock.Setup(x => x.GetModule(lessonId)).Returns(module);
var lessonService = new LessonService(lessonRepositoryMock.Object, moduleRepositoryMock.Object);
//Act
lessonService.UpdateLessonGrade(12, 98.2d);
//Assert
Assert.IsTrue(lesson.IsPassed); // assuming it should pass in this condition
Assert.AreEqual(98.2d, lesson.Grade); // expected Lesson Grade should be what you expected the grade to be after you call UpdateLessonGrade
}
I'm on a mobile device right now, I can try to update the answer later this weekend, but this should get you started.
Refactor your method to use instance variables instead of direct instantiation in the method. Add them as parameters to your constructor. In the main method create your repository instances and pass them to the service constructor.
Now you can use something like Moq or the in memory provider for entity framework.
As for what to test, basically test every piece of branching logic. At a minimum, each piece of an if statement and the else conditions. You should also test what happens when your repository objects don't find what you're looking for (e.g. returns null). Offhand, I'm counting at least six tests.
Update: Bravo! Looking at your updated code in the question, everything is on the right track.
In your test method, you'll want to add:
var foodService = new FoodService(foodRepositoryMock.Object, drinkRepositoryMock.Object);
That will initialize your service with the mock objects.
Then you'll want to call your service with test parameters like:
foodService.UpdateFoodGrade(12, 98.2d);
The last part is check your food object using asserts like:
Assert.IsTrue(food.IsPassed) // assuming it should pass in this condition
Assert.Equals(98.2d, food.Grade); // expectedFoodGrade should be what you expected the grade to be after you call UpdateFoodGrade
It looks like you'll also need to flesh out the instance of your Drink object a little bit more. You need to specify a value for MinimumPassingGrade since it's used to drive the decision logic in your if statement, for example, if you want the food.IsPassed = true to trigger, you would instantiate the drink object like so:
var drink = new Drink() { DrinkId = foodId, MinimumPassingGrade = 50.0d };
You would create test methods for each of the other various test cases, failed the minimum, when it's equal to the score, if you can't find the food in the food repo, or the drink in the drink repo, etc.
One other note, you only need to worry about Verifiable mocks when you need to know that a method was/wasn't called. For these tests, I probably wouldn't verify that methods were called (creates tighter coupling between your test and the implementation vs. the behavior). You'd want to verify that the methods were called only if something in your service code truly depends on knowing that it was called. e.g. if you're using Entity Framework and you wanted to make sure you didn't forget to call SaveChanges().
Indeed, such code can't be "normally" unit-tested without preliminary refactoring. But you still have one (bit dirty) option: Shims mechanism of MS Fakes Library.
It allows you to substitute any method or property of any type (including static, non-public and system) with any arbitrary code. In your case you may create a ShimsContext in you test method, and give some fake behavior for FoodRepository.GetFood() and DrinkRepository.GetDrink() methods, for example, empty body doing nothing. So, when your test runs, your stub code gonna be executed instead of the actual code of repository classes. So you will test only Service code without executing code of repositories.
You may check this article for quick introduction to the library.
And please keep in mind that Shims is not a way of good unit-testing, It is just a tool to deal with such non-testable code in case when you absolutely need to unit-test it somehow without changing the code itself.

TDD - Using properties to auto-generate code

I am practicing TDD using MsTest together with RhinoMocks, and I am trying to be as lazy as humanly possible, i.e. make use of VS2012 auto-generation wherever I can. But it doesn't always feel right to create an entire test method with the Arrange-Act-Assert methodology, just to set up my class and its constructors and properties.
Currently, I find it easiest to create some properties in my test class - even if I don't use them - solely for the purpose of code generation. My question is, is this a bad habit, and is there a better/easier way to do it? Any commentary, good or bad is welcome; Thank you!
[TestClass]
public class MainViewModelTest
{
private MainViewModel MainViewModel
{
get
{
var facilityDataEntity = MockRepository.GenerateStub<FacilityDataEntity>();
var viewModel = new MainViewModel(facilityDataEntity)
{
FacilityValue = string.Empty,
FacilityLabel = string.Empty
};
return viewModel;
}
}
private MainViewModel MainViewModelWithFacilityAndShopOrderData
{
get
{
var facilityDataEntity = MockRepository.GenerateStub<FacilityDataEntity>();
var shopOrderDataEntity = MockRepository.GenerateStub<ShopOrderDataEntity>();
var viewModel = new MainViewModel(facilityDataEntity, shopOrderDataEntity)
{
FacilityValue = string.Empty,
FacilityLabel = string.Empty,
ShopOrder = 99999999,
RequiredQuantity = 0M,
ItemCode = string.Empty,
ItemDescription = string.Empty
};
return viewModel;
}
}
[TestMethod]
public void MainViewModel_TranslateDataEntityListMethodReturnsMainViewModelRecords()
{
// Arrange
var facilityDataEntityList = MockRepository.GenerateStub<IEnumerable<FacilityDataEntity>>();
var shopOrderDataEntityList = MockRepository.GenerateStub<IEnumerable<ShopOrderDataEntity>>();
// Act
IEnumerable<MainViewModel> facilityResults = MainViewModel.TranslateDataEntityList(facilityDataEntityList);
IEnumerable<MainViewModel> shopOrderResults = MainViewModel.TranslateDataEntityList(facilityDataEntityList, shopOrderDataEntityList);
// Assert
Assert.IsInstanceOfType(facilityResults, typeof(IEnumerable<MainViewModel>));
Assert.IsInstanceOfType(shopOrderResults, typeof(IEnumerable<MainViewModel>));
}
}
It's not wrong to wrap up common code within your test classes, but I would avoid potentially sharing state between your tests.
There are two approaches you can use here.
Class/Test Initialization
As Peter mentions in his comments, it's easy enough to include initialization methods to do this sort of stuff for you.
//Only runs once per test run
[ClassInitialize]
public void InitClass(){
//Ideally this should be reserved for expensive operations
// or for setting properties that are static throughout
// the lifetime of your test.
}
//Runs for every test
[TestInitialize]
public void TestInit(){
//Here you can setup common stub/mock behavior
// that will be common for every test, but ensure
// it is clean for each test run
}
Setup/Factory Methods
Another option is to create specialized setup or factory methods that can be used to reduce repeated test code and make the intent of your test clearer.
[TestMethod]
public void ShouldFailIfUserNameIsTed(){
var user = SetupUserScenario("Ted");
var result = _myUserService.Validate(user);
Assert.IsFalse(result);
}
private User SetupUserScenario(String username){
var user = new User();
user.Name = username;
//Do a bunch of other necessary setup
return user;
}
Hopefully this all makes sense, but I would also caution you not to go too crazy with this. If you put too much stuff into setup methods, then your tests will be less clear. You should be able to read the test and figure out what is going on without having to inspect a bunch of other places in the code.
That's what the ClassInitialize functionality is for. I would choose expected and recommended means of doing something before anything else. It's more easily recognizable and takes less time to grok the code.

How to find places in code that must be covered with unit tests

I know it's not so good to write tests after you actually wrote code. I'm unit-testing newbie and feel that unit-testing may deliver many good advantages so I obsessed with an idea to cover as much as possible.
For instance, let we have this code:
public class ProjectsPresenter : IProjectsViewObserver
{
private readonly IProjectsView _view;
private readonly IProjectsRepository _repository;
public ProjectsPresenter(IProjectsRepository repository, IProjectsView view)
{
_view = view;
_repository = repository;
Start();
}
public void Start()
{
_view.projects = _repository.FetchAll();
_view.AttachPresenter(this);
}
}
So looking on code above could you answer me what tests typically I should write on that piece of the code above?
I'm rolling on write tests on constructor to make sure that repository's FetchAll was called and on the view site AttachPresenter is called.
POST EDIT
Here is a my view interface:
public interface IProjectsView
{
List<Project> projects { set; }
Project project { set; }
void AttachPresenter(IProjectsViewObserver projectsPresenter);
}
Here is a view:
public partial class ProjectsForm : DockContent, IProjectsView
{
private IProjectsViewObserver _presenter;
public ProjectsForm()
{
InitializeComponent();
}
public Project project
{
set
{
listBoxProjects.SelectedItem = value;
}
}
public List<Project> projects
{
set
{
listBoxProjects.Items.Clear();
if ((value != null) && (value.Count() > 0))
listBoxProjects.Items.AddRange(value.ToArray());
}
}
public void AttachPresenter(IProjectsViewObserver projectsPresenter)
{
if (projectsPresenter == null)
throw new ArgumentNullException("projectsPresenter");
_presenter = projectsPresenter;
}
private void listBoxProjects_SelectedValueChanged(object sender, EventArgs e)
{
if (_presenter != null)
_presenter.SelectedProjectChanged((Project)listBoxProjects.SelectedItem);
}
}
POST EDIT #2
This is how I test interaction with repository. Is everything allright?
[Test]
public void ProjectsPresenter_RegularProjectsProcessing_ViewProjectsAreSetCorrectly()
{
// Arrange
MockRepository mocks = new MockRepository();
var view = mocks.StrictMock<IProjectsView>();
var repository = mocks.StrictMock<IProjectsRepository>();
List<Project> projList = new List<Project> {
new Project { ID = 1, Name = "test1", CreateTimestamp = DateTime.Now },
new Project { ID = 2, Name = "test2", CreateTimestamp = DateTime.Now }
};
Expect.Call(repository.FetchAll()).Return(projList);
Expect.Call(view.projects = projList);
Expect.Call(delegate { view.AttachPresenter(null); }).IgnoreArguments();
mocks.ReplayAll();
// Act
ProjectsPresenter presenter = new ProjectsPresenter(repository, view);
// Assert
mocks.VerifyAll();
}
I know it's not so good to write tests after you actually wrote code
It's better than not writing tests at all.
Your method works with two external components and that interaction should be verified (in addition to mentioned arguments validation). Checking whether FetchAll was called gives you no value (or checking it returns something - this belongs to ProjectsRepository tests itself) - you want to check that view's projects are set (which will indirectly check whether FetchAll was called). Tests you need are:
verify that view projects are set to expected value
verify that presenter is attached
validate input arguments
Edit: example of how you would test first case (projects are set)
// "RegularProcessing" in test name feels a bit forced;
// in such cases, you can simply skip 'conditions' part of test name
public void ProjectsPresenter_SetsViewProjectsCorrectly()
{
var view = MockRepository.GenerateMock<IProjectView>();
var repository = MockRepository.GenerateMock<IProjectsRepository>();
// Don't even need content;
// reference comparison will be enough
List<Project> projects = new List<Project>();
// We use repository in stub mode;
// it will simply provide data and that's all
repository.Stub(r => r.FetchAll()).Return(projects);
view.Expect(v => v.projects = projects);
ProjectsPresenter presenter = new ProjectsPresenter(repository, view);
view.VerifyAllExpecations();
}
In second case, you'll set expectations on view that its AttachPresenter is called with valid object:
public void ProjectsPresenter_AttachesPresenterToView()
{
// Arrange
var view = MockRepository.GenerateMock<IProjectView>();
view.Expect(v => v.AttachPresenter(Arg<IProjectsViewObserver>.Is.Anything));
var repository = MockRepository.GenerateMock<IProjectsRepository>();
// Act
var presenter = new ProjectsPresenter(repository, view);
// Assert
view.VerifyAllExpectations();
}
I would add simple tests at start , like:
null reference checks
FetchAll() returns any value
Do not add a lot of test code at first time, but refine them after as your dev code mutates.
I would add tests for exception e.g. ArgumentException, corner cases and usual ones of FetchAll().
PS. Does start have to be public?
Pex is an interesting tool that's worth checking out. It can generate suites of unit tests with high code coverage: http://research.microsoft.com/en-us/projects/pex/. It doesn't replace your own knowledge of your code - and which test scenarios are more important to you than others - but it's a nice addition to that.
The purpose of writing tests before writing production code is first and foremost to put you (the developer) in the mind-set of "how will i know when my code works?" When your development is focused on what the result of what working code will look like and not the code itself you are focused on the actual business value obtained by your code and not extraneous concerns (millions of man hours have been spent building and maintaining features users never asked for, wanted, or needed). When you do this you are doing "test driven development".
If you are doing pure TDD the answer is 100% code coverage. That is you do not write a single line of production code that is not already covered by a line of unit test code.
In Visual Studio if you go to Test->Analyze Code Coverage it will show you all of the lines of code that you do not have covered.
Practically speaking its not always feasible to enforce 100% code coverage. Also there are some lines of code that are much more important then others. Determining which depends once again on the business value provided by each line and the consequence of that line failing. Some lines (like logging) may have a smaller consequence then others.

How do I check "no exception occurred" in my MSTest unit test?

I'm writing a unit test for this one method which returns "void". I would like to have one case that the test passes when there is no exception thrown. How do I write that in C#?
Assert.IsTrue(????)
(My guess is this is how I should check, but what goes into "???")
I hope my question is clear enough.
Your unit test will fail anyway if an exception is thrown - you don't need to put in a special assert.
This is one of the few scenarios where you will see unit tests with no assertions at all - the test will implicitly fail if an exception is raised.
However, if you really did want to write an assertion for this - perhaps to be able to catch the exception and report "expected no exception but got this...", you can do this:
[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
var myObject = new MyObject();
try
{
myObject.MethodUnderTest();
}
catch (Exception ex)
{
Assert.Fail("Expected no exception, but got: " + ex.Message);
}
}
(the above is an example for NUnit, but the same holds true for MSTest)
In NUnit, you can use:
Assert.DoesNotThrow(<expression>);
to assert that your code does not throw an exception. Although the test would fail if an exception is thrown even if there was no Assert around it, the value of this approach is that you can then distinguish between unmet expectations and bugs in your tests, and you have the option of adding a custom message that will be displayed in your test output. A well-worded test output can help you locate errors in your code that have caused a test to fail.
I think it's valid to add tests to ensure that your code is not throwing exceptions; for example, imagine you are validating input and need to convert an incoming string to a long. There may be occasions when the string is null, and this is acceptable, so you want to ensure that the string conversion does not throw an exception. There will therefore be code to handle this occasion, and if you haven't written a test for it you will be missing coverage around an important piece of logic.
This helper class scratched my itch with MSTest. Maybe it can scratch yours also.
[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
// Arrange
var factory = new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
// Assert
AssertEx.NoExceptionThrown<FormatException>(() =>
// Act
_service.ScheduleJob(scheduler)
);
}
public sealed class AssertEx
{
public static void NoExceptionThrown<T>(Action a) where T:Exception
{
try
{
a();
}
catch (T)
{
Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
}
}
}
Don't test that something doesn't happen. It's like assuring that code doesn't break. That's sort of implied, we all strive for non-breaking, bug-less code. You want to write tests for that? Why just one method? Don't you want all your methods being tested that they don't throw some exception? Following that road, you'll end up with one extra, dummy, assert-less test for every method in your code base. It brings no value.
Of course, if your requirement is to verify method does catch exceptions, you do test that (or reversing it a bit; test that it does not throw what it is supposed to catch).
However, the general approach/practices remain intact - you don't write tests for some artificial/vague requirements that are out of scope of tested code (and testing that "it works" or "doesn't throw" is usually an example of such - especially in scenario when method's responsibilities are well known).
To put it simple - focus on what your code has to do and test for that.
I like to see an Assert.Whatever at the end of each test, just for consistency... without one, can I really be sure there's not supposed to be one there?
For me, this is as simple as putting Assert.IsTrue(true);
I know I didn't accidentally put that code in there, and thus I should be confident enough at quick a skim through that this was as intended.
[TestMethod]
public void ProjectRejectsGappedVersioningByDefault() {
var files = new List<ScriptFile>();
files.Add(ScriptProjectTestMocks.GetVersion1to2());
files.Add(ScriptProjectTestMocks.GetVersion3to4());
Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
var sut = new ScriptProject(files);
});
}
[TestMethod]
public void ProjectAcceptsGappedVersionsExplicitly() {
var files = new List<ScriptFile>();
files.Add(ScriptProjectTestMocks.GetVersion1to2());
files.Add(ScriptProjectTestMocks.GetVersion3to4());
var sut = new ScriptProject(files, true);
Assert.IsTrue(true); // Assert.Pass() would be nicer... build it in if you like
}
My friend Tim told me about ExpectedException. I really like this b/c it is more succinct, less code, and very explicit that you are testing for an exception.
[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
int numerator = 4;
int denominator = 0;
int actual = numerator / denominator;
}
You can read way more about it here: ExpectedException Attribute Usage.
With Xunit you can use this:
var exception = Record.Exception(() =>
MethodUnderTest());
Assert.Null(exception);
or for async operations
var exception = await Record.ExceptionAsync(async () =>
await MethodUnderTestAsync());
Assert.Null(exception);
Another way which worked for me is to store it in a variable and check output.
var result = service.Run()
Assert.IsFalse(result.Errors.Any())
using Moq;
using Xunit;
[Fact]
public void UnitTest_DoesNotThrow_Exception()
{
var builder = new Mock<ISomething>().Object;
//Act
var exception = Record.Exception(() => builder.SomeMethod());
//Assert
Assert.Null(exception);
}

Proper way to verify parameters being passed to a Mock are set as expected

Is it acceptable to do asserts in your callbacks if you later verify that the methods were called? Is this the preferred way of making sure my mock is getting the expected parameters passed to it, or should I set a local variable in my callback and do the asserts on that instance?
I have a situation where I have some logic in a Presenter class that derives values based on inputs and passes them to a Creator class. To test the logic in the Presenter class I want to verify that the proper derived values are observed when the Creator is called. I came up with the example below that works, but I'm not sure if I like this approach:
[TestFixture]
public class WidgetCreatorPresenterTester
{
[Test]
public void Properly_Generates_DerivedName()
{
var widgetCreator = new Mock<IWidgetCreator>();
widgetCreator.Setup(a => a.Create(It.IsAny<Widget>()))
.Callback((Widget widget) =>
Assert.AreEqual("Derived.Name", widget.DerivedName));
var presenter = new WidgetCreatorPresenter(widgetCreator.Object);
presenter.Save("Name");
widgetCreator.Verify(a => a.Create(It.IsAny<Widget>()), Times.Once());
}
}
I'm concerned because without the Verify call at the end, there is no guarantee that the assert in the callback would be invoked. Another approach would be to set a local variable in the callback:
[Test]
public void Properly_Generates_DerivedName()
{
var widgetCreator = new Mock<IWidgetCreator>();
Widget localWidget = null;
widgetCreator.Setup(a => a.Create(It.IsAny<Widget>()))
.Callback((Widget widget) => localWidget = widget);
var presenter = new WidgetCreatorPresenter(widgetCreator.Object);
presenter.Save("Name");
widgetCreator.Verify(a => a.Create(It.IsAny<Widget>()), Times.Once());
Assert.IsNotNull(localWidget);
Assert.AreEqual("Derived.Name", localWidget.DerivedName);
}
I feel that this approach is less error prone since it is more explicit, and it's easier to see that the Assert statements will be called. Is one approach preferable to the other? Is there a simpler way to test the input parameter passed to a mock that I'm missing?
In case it is helpful, here is the rest of the code for this example:
public class Widget
{
public string Name { get; set; }
public string DerivedName { get; set; }
}
public class WidgetCreatorPresenter
{
private readonly IWidgetCreator _creator;
public WidgetCreatorPresenter(IWidgetCreator creator)
{
_creator = creator;
}
public void Save(string name)
{
_creator.Create(
new Widget { Name = name, DerivedName = GetDerivedName(name) });
}
//This is the method I want to test
private static string GetDerivedName(string name)
{
return string.Format("Derived.{0}", name);
}
}
public interface IWidgetCreator
{
void Create(Widget widget);
}
EDIT
I updated the code to make the second approach I outlined in the question easier to use. I pulled creation of the expression used in Setup/Verify into a separate variable so I only have to define it once. I feel like this method is what I'm most comfortable with, it's easy to setup and fails with good error messages.
[Test]
public void Properly_Generates_DerivedName()
{
var widgetCreator = new Mock<IWidgetCreator>();
Widget localWidget = null;
Expression<Action<IWidgetCreator>> expressionCreate =
(w => w.Create(It.IsAny<Widget>()));
widgetCreator.Setup(expressionCreate)
.Callback((Widget widget) => localWidget = widget);
var presenter = new WidgetCreatorPresenter(widgetCreator.Object);
presenter.Save("Name");
widgetCreator.Verify(expressionCreate, Times.Once());
Assert.IsNotNull(localWidget);
Assert.AreEqual("Derived.Name", localWidget.DerivedName);
}
What I do is do the Verify with matches in keeping with AAA. And becuase of this the Setup is not required. You can inline it but I separated it out to make it look cleaner.
[Test]
public void Properly_Generates_DerivedName()
{
var widgetCreator = new Mock<IWidgetCreator>();
var presenter = new WidgetCreatorPresenter(widgetCreator.Object);
presenter.Save("Name");
widgetCreator.Verify(a => a.Create(MatchesWidget("Derived.Name"));
}
private Widget MatchesWidget(string derivedName)
{
return It.Is<Widget>(m => m.DerivedName == derivedName);
}
Because of the way your code is structured, you're kind of forced to test two things in one unit test. You're testing that A) your presenter is calling the injected WidgetCreator's create method and B) that the correct name is set on the new Widget. If possible, it'd be better if you can somehow make these two things two separate tests, but in this case I don't really see a way to do that.
Given all that, I think the second approach is cleaner. It's more explicit as to what you're expecting, and if it fails, it'd make perfect sense why and where it's failing.
Just to elaborate on #rsbarro's comment - the Moq failure error message:
Expected invocation on the mock at least once, but was never performed
... is less than helpful for complex types, when determining exactly which condition actually failed, when hunting down a bug (whether in the code or unit test).
I often encounter this when using Moq Verify to verify a large number of conditions in the Verify, where the method must have been called with specific parameter values which are not primitives like int or string.
(This is not typically a problem for primitive types, since Moq lists the actual "performed invocations" on the method as part of the exception).
As a result, in this instance, I would need to capture the parameters passed in (which to me seems to duplicate the work of Moq), or just move the Assertion inline with Setup / Callbacks.
e.g. the Verification:
widgetCreator.Verify(wc => wc.Create(
It.Is<Widget>(w => w.DerivedName == "Derived.Name"
&& w.SomeOtherCondition == true),
It.Is<AnotherParam>(ap => ap.AnotherCondition == true),
Times.Exactly(1));
Would be recoded as
widgetCreator.Setup(wc => wc.Create(It.IsAny<Widget>(),
It.IsAny<AnotherParam>())
.Callback<Widget, AnotherParam>(
(w, ap) =>
{
Assert.AreEqual("Derived.Name", w.DerivedName);
Assert.IsTrue(w.SomeOtherCondition);
Assert.IsTrue(ap.AnotherCondition, "Oops");
});
// *** Act => invoking the method on the CUT goes here
// Assert + Verify - cater for rsbarro's concern that the Callback might not have happened at all
widgetCreator.Verify(wc => wc.Create(It.IsAny<Widget>(), It.Is<AnotherParam>()),
Times.Exactly(1));
At first glance, this violates AAA, since we are putting the Assert inline with the Arrange (although the callback is only invoked during the Act), but at least we can get to the bottom of the issue.
Also see Hady's idea of moving the 'tracking' callback lambda into its own named function, or better still, in C#7, this can be moved to a Local Function at the bottom of the unit test method, so the AAA layout can be retained.
Building on top of StuartLC's answer in this thread, you follow what he is suggesting without violating AAA by writing an "inline" function that is passed to the Verify method of a mock object.
So for example:
// Arrange
widgetCreator
.Setup(wc => wc.Create(It.IsAny<Widget>(), It.IsAny<AnotherParam>());
// Act
// Invoke action under test here...
// Assert
Func<Widget, bool> AssertWidget = request =>
{
Assert.AreEqual("Derived.Name", w.DerivedName);
Assert.IsTrue(w.SomeOtherCondition);
Assert.IsTrue(ap.AnotherCondition, "Oops");
return true;
};
widgetCreator
.Verify(wc => wc.Create(It.Is<Widget>(w => AssertWidget(w)), It.Is<AnotherParam>()), Times.Exactly(1));

Categories