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.
Related
I have the following function that I am trying to put under unit test
public MessageListDto GetMessageList(SimpleSearchCriteria criteria)
{
var messages = _repository.GetMessages(criteria, out int total);
return new MessageListDto(messages, total);
}
and the following is my test so far, in which I am able to determine that _repository.GetMessages is call with the correct parameters.
However, how do I test that the second line is tested properly, I need to test that
A new object of type MessageListDto is constructed with the two parameters returned from the line above
the newly constructed object is returned
[Test]
public void Test1()
{
int total = 10;
var searchCriteria = new SimpleSearchCriteria();
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
messageService.GetMessageList(searchCriteria);
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);
mockRepo.Verity ??????????
}
As we have discussed in the comment section your goal is to test the returned messages is passed to the dto's constructor without any modification.
With your current code you can't do that because you are creating the DTO explicitly inside your method. So, you can't replace it with a spy.
Just to clarify some terminologies:
Dummy: simple code that returns bogus data
Fake: a working alternative which can take shortcuts
Stub: custom logic with predefined data
Mock: custom logic with expectations (interactive stub)
Shim: custom logic at run-time
Spy: interceptors to record calls
To be able to capture the arguments of the MessageListDto constructor call you need to introduce an other layer between your GetMessageList method and the constructor. (In other words indirection)
For the sake of simplicity let me assume that IMessageRepository's GetMessages returns a string array.
So, you can introduce an interface like this:
public interface IDtoProvider
{
public MessageListDto CreateMessageList(string[] messages, int total)
=> new MessageListDto(messages, total);
}
Here I have used C# 8's interface default implementation feature
It can be further shortened with C# 9's target-typed new expression feature
If you are using older C# version then you need to separate the interface and the default implementation from each other
Now lets amend your MessageService to receive a IDtoProvider instance via its constructor
class MessageService
{
private readonly IMessageRepository _repository;
private readonly IDtoProvider _dtoProvider;
public MessageService(IMessageRepository repository, IDtoProvider dtoProvider)
=> (_repository, _dtoProvider) = (repository, dtoProvider);
public MessageListDto GetMessageList(SimpleSearchCriteria criteria)
{
var messages = _repository.GetMessages(criteria, out int total);
return _dtoProvider.CreateMessageList(messages, total);
}
...
}
Here I've took advantage of ValueTuple's deconstruct capability
With these in our hand we can write a unit test like this:
//Arrange - Repo
string[] messages = new[] { "OnlyElement" };
int total = 10;
var mockRepo = new Mock<IMessageRepository>();
mockRepo
.Setup(repo => repo.GetMessages(It.IsAny<SimpleSearchCriteria>(), out total))
.Returns(messages);
//Arrange - Provider
var dto = new MessageListDto(messages, total);
string[] messagesArgument = null;
int totalArgument = -1;
var mockProvider = new Mock<IDtoProvider>();
mockProvider
.Setup(provider => provider.CreateMessageList(It.IsAny<string[]>(), It.IsAny<int>()))
.Callback<string[], int>((messages, total) => (messagesArgument, totalArgument) = (messages, total))
.Returns(dto);
//Arrange - SUT
var searchCriteria = new SimpleSearchCriteria();
var sut = new MessageService(mockRepo.Object, mockProvider.Object);
//Act
sut.GetMessageList(searchCriteria);
//Assert - Repo
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);
//Assert - Provider
Assert.Equal(messages, messagesArgument);
Assert.Equal(total, totalArgument);
I've defined how should the IMessageRepository mock behave
I've defined how should the IDtoProvider mock behave
2.1 I've used here the Callback method to capture the calling argument
2.2 If you perform multiple calls against your mocked method then please consider to use Capture.In
I've instantiated a MessageService (which is our system under test) with the mock objects
I've called the GetMessageList inside the Act phase
I've made assertion against the repo mock call
I've made assertion against the calling parameters of the CreateMessageList
6.1 Here I have used xunit's assertion
The first step is to setup the MessageService mock, so that it returns something deterministic and then in the second step you verify that that has been used to construct your MessageListDto.
[Test]
public void Test1()
{
// arrange
int total = 10;
var searchCriteria = new SimpleSearchCriteria();
var messages = new [] {"message1", "message2"} // or similar
var mockRepo = new Mock<IMessageRepository>();
// or similar, I am not quite certain as to the specific syntax. Especially wrt. out parameters. Check the documentation.
mockRepo.Setup(x => x.GetMessages(It.IsAny<SimpleSearchCriteria>(), It.IsAny<int>())).Returns(messages);
var messageService = new MessageService(mockRepo.Object);
// act
var result = messageService.GetMessageList(searchCriteria);
// assert
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);
// or similar; here you might want to check out FluentAssertions as #Peter Csala suggested
Assert.Equal(result.Messages, messages);
}
What's missing from previous answers is that whenever possible, you should set up the mocked method with the exact parameters, that you expect it to receive. In other words set up the method with concrete values instead of It.IsAny<>(). In such case you won't have to verify the method later at all. (Unless it's critical to test, how many times a method is called). Simply, if mocked GetMessages receives different arguments than expected, it will return null, set total to 0 and your test will fail. Having the mocked methods set up properly, you can now focus on verifying what GetMessageList returns, which is the purpose of this unit test.
[Test]
public void Test1()
{
int total = 10;
var messages = new[] {new Message()};
var searchCriteria = new SimpleSearchCriteria();
var mockRepo = new Mock<IMessageRepository>();
mockRepo.Setup(_ => _.GetMessages(searchCriteria, out total))
.Returns(messages);
var messageService = new MessageService(mockRepo.Object);
var dto = messageService.GetMessageList(searchCriteria);
Assert.AreSame(messages, dto.Messages);
Assert.AreEqual(total, dto.Total);
}
I am unit-testing an async method that returns a List<T>. This method has a dependency on a mapping class/interface. In my unit-test, I am mocking the mapping class using moq. The test runs okay, and the returned list has items, but the values of the items is null. I think the problem is because I haven't stubbed-out the mapping classes methods properly. I don't have a lot of experience with testing, so any guidance is appreciated.
Test Method:
[TestMethod]
[TestCategory("CSR.Data.Tests.Services.ServiceSearchTest")]
public void SearchAccount()
{
// Arrange
var mapper = new Mock<CSR.Data.Mapping.Interfaces.IMapper<Account, AccountDTO>>();
mapper.Setup(i => i.Initialize());
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(It.IsAny<Account>);
mapper.Setup(i => i.DomainToDto(It.IsAny<Account>())).Returns(It.IsAny<AccountDTO>);
var service = new ServiceSearch(null,mapper.Object);
string accountNumber = "123";
string accountName = "";
// Act
var results = service.SearchAccount(accountNumber, accountName);
// Assert
Assert.IsTrue(results.Result.Count >= 1);
}
Method/Class That I'm Testing:
public class ServiceSearch : IServiceSearch
{
public ServiceSearch(IMapper<Claim, ClaimDTO> claimMapper, IMapper<Account, AccountDTO> accountMapper)
{
_claimMapper = claimMapper;
_accountMapper = accountMapper;
}
public async Task<List<AccountDTO>> SearchAccount(string accountNumber, string accountName)
{
var accounts = new List<Account>();
var accountDTOs = new List<AccountDTO>();
var results = await Task.Run(() => base.AccountSearch(accountNumber, accountName).Result);
if (results != null && results.Count > 0)
{
//Map DH to Domain
_accountMapper.Initialize();
foreach (AccountSearchResult result in results)
{
accounts.Add(_accountMapper.ToDomain(result));
}
//Map Domain to DTO
foreach (Account account in accounts)
{
accountDTOs.Add(_accountMapper.DomainToDto(account));
}
}
return accountDTOs;
}
}
This isn't the best place to use a Mock object because you are going to spend a lot of time writing your test objects and mock results. The issue with the setup call is that you haven't configured anything to send back in the result. A correct example would be:
// you would fully configure this object
AccountDTO expectedResult = new AccountDTO();
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(expectedResult);
Now you can use the setup to configure different accountDTOs for different inputs.
You call also configure a callback to generate the account at test time:
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns<AccountSearchResult>(sr => {
// build and return your dto here
});
However, unless your mapper is expensive to run or create, I think you'd better off just ensure that it is fully tested and acceptable and then use it to go ahead and generate the DTOs directly instead of trying to mock it out.
You don't actually setup an object in the ".Returns" call. You need to make sure to setup the ".Returns" to actually have an object with values.
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.
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.
Using the new Rhino Mocks 3.5 Arrange/Act/Assert (AAA) Testing style, I'm having problems writing a test.
I have a method that calls a method on a repository class. ActivateFoo, where my Foo object has an IsActive property. The result of the ActivateFoo object should change the property.
Here is sample code:
[TestMethod]
public void Should_update_foo_to_active_inside_of_repository()
{
// arrange
var repo = MockRepository.GenerateMock<IRepository>();
var foo = new Foo() { ID = 1, IsActive = false };
var target = new Presenter(repo);
repo.Expect(x => x.ActivateFoo(foo)).Return(true);
// act
target.Activate(foo);
// assert
Assert.IsTrue(foo.IsActive);
repo.VerifyAllExpectations();
}
I'm guessing that the key piece of code would be inbetween "ActivateFoo(foo))." and "Return(true);".
One point to clarify how the method chaining stuff works behind the scenes, If there is code written on the line I expect, does it matter if it is after Return() or before? (unless of course the solution is using the MethodOptions overload of Expect, or something else).
Thanks in advance for any help.
Thanks to AB Kolan this is the resulting code I used and works.
[TestMethod]
public void Should_update_foo_to_active_inside_of_repository()
{
// arrange
var repo = MockRepository.GenerateMock<IRepository>();
var foo = new Foo() { ID = 1, IsActive = false };
var target = new Presenter(repo);
repo.Expect(x => x.ActivateFoo(foo)).
Do(new Func<Foo, bool>(
delegate(Foo f) { f.IsActive = true; return true; }
));
// act
target.Activate(foo);
// assert
Assert.IsTrue(foo.IsActive);
repo.VerifyAllExpectations();
}
I tend to not like to have to have extra methods of functions for single use of a test, preferring an inline delegate if possible.
To address the issue of is this something I should be doing or not as far as the design. As the names are there, this isn't the exact code and inside of the target.Activate() method. The code in Activate() does some checking and if needed, will do the repository ActivateFoo(), and then check the result of that operation and do other things.
So, it might be possible that at a later time I will have to refactor this out and separate the steps, but for now, I've got it to work.
Thanks
You might want to try something out like this using the Do handler. I honestly feel ActivateFoo should be void return type. But here's the code for ActivateFoo with bool return type.
[TestMethod]
public void Should_update_foo_to_active_inside_of_repository()
{
// arrange
var repo = MockRepository.GenerateMock<IRepository>();
var foo = new Foo() { ID = 1, IsActive = false };
var target = new Presenter(repo);
repo.Expect(x => x.ActivateFoo(foo)).
Do(new ActivateFooDelegate(ActivateFooDelegateInstance));
// act
target.Activate(foo);
// assert
Assert.IsTrue(foo.IsActive);
repo.VerifyAllExpectations();
}
private delegate bool ActivateFooDelegate(Foo f);
public bool ActivateFooDelegateInstance(Foo f)
{
f.IsActive = true;
return f.IsActive;
}
I was not really using this version of RhinoMocks yet, but in the old versions you would have to use a .Do(appropriate delegate) to set the flag and return the value (instead of .Return).
Please let me know if it works, if not I can play around with it.
From the looks of it, ActivateFoo should be a void method. And since you are mocking it out, you shouldn't be verifying that it changes anything on your object.
You would verify that the IsActive property is changed when you were testing your repository method ActivateFoo, not when you are testing the Activate method on the presenter.