Can't stub a ReadOnly property twice? - c#

I have the following code. I have a somewhat legitimate reason for stubbing that property twice (See explanation below). It looks like it's only letting me stub it once.
private IStatus _status;
[SetUp()]
public void Setup() {
this._status = MockRepository.GenerateStub<IStatus>();
this._status.Stub(x => x.Connected()).Return(true);
// This next line would usually be in the Setup for a subclass
this._status.Stub(x => x.Connected()).Return(false);
}
[Test()]
public void TestTheTestFramework() {
Assert.IsFalse(this._status.Connected()); // Fails...
}
public interface IStatus {
bool Connected { get; }
}
I tried downloading the most recent build (3.6 build 21), but still have the same issue. Any ideas on why I can't do this? I tried changing the Connected property on IStatus to be a function and the test still failed. I get the same behavior in VB.Net... Bug?
Explanation on the double-stubbing
I'm structuring my tests around inheritance. That way I can do common setup code just once, using injected mocked dependencies to simulate different conditions. I might provide a base/default stubbed value (e.g. yes, we're connected) which I'd want to override in the subclass that tests the behavior of the SUT when the connection is down. I usually end up with code like this.
[TestFixture()]
public class WhenPublishingAMessage {
// Common setup, inject SUT with mocked dependencies, etc...
[Test()]
public void ShouldAlwaysWriteLogMessage {
//Example of test that would pass for any sub-condition
}
[TestFixture()]
public class AndNoConnection : WhenPublishingAMessage {
// Do any additional setup, stub dependencies to simulate no connection
// Run tests for this condition
}
[TestFixture()]
public class AndHaveConnection : WhenPublishingAMessage {
// Do any additional setup and run tests for this condition
}
}
Edit
This post on the Rhino Mocks google group might be helpful. It looks like I might need to call this._status.BackToRecord(); to reset the state, so to speak... also, tacking on .Repeat.Any() to the second stub statement seemed to help as well. I'll have to post more details later.

You can specify .Repeat.Once() on the first result so that it will be used once and then the next one, as explained in this other stack overflow question

To sum everything up, there's a three different answers that are possible:
Tallmaris's answer:
Specify a specific number of times to return on the first stub using .Repeat.Times(n), .Repeat.Once(), .Repeat.Twice(), etc. For example:
this._status.Stub(x => x.Connected()).Return(true).Repeat.Once();
this._status.Stub(x => x.Connected()).Return(false);
This method works pretty well if I know the number of times the stub will get called before I change it's behavior (e.g. it just gets called once in the constructor).
Reset the mocked object
I don't like this method since I'd like to avoid the (at least to me) more cumbersome Expect/Verify Record/Replay type syntax. It was recommending to me in response to a post I made to the Rhino Mocks Google group with the same title as this question.
this._status.Stub(x => x.Connected).Return(true);
this._status.GetMockRepository().BackToRecordAll();
this._status.GetMockRepository().ReplayAll();
this._status.Stub(x => x.Connected).Return(false);
Using the magical Repeat.Any
I found that using .Repeat.Any() on the second stub overrode the first one work... I feel a bit bad adding some extra 'magic' code to make it work, but in the case where you don't know how often to tell the first stub to return, this option will work.
this._status.Stub(x => x.Connected()).Return(true);
this._status.Stub(x => x.Connected()).Return(false).Repeat.Any();
Note: you can't do .Repeat.Any() more than once.

Related

Unit testing classes with mocked repository dependecies

I have a service class with several methods. Service has some dependencies on repositories. I am using Moq to mock the repository. I have a problem with the proper unit testing one of the methods. I will give you an example:
public interface IRepository<T>
{
IEnumerable<T> FindAll();
IEnumerable<T> FindByQuery(Predicate<T> predicate);
//many other methods for retreiving T's
}
public class MyService
{
private readonly IRepository<Category> _repo;
public MyService(IRepository<Category> repo)
{
_repo = repo;
}
public List<Category> FindActiveCategories()
{
return _repo.FindAll().Where(x => x.Active).ToList();
}
}
Now, I wrote a unit test:
public FindActiveCategories_WhenCalled_ShouldReturnActiveCategories() {
var moq = new Mock<IRepository<Category>>();
var list = new List<Category>
{
new Category {Active = true},
new Category {Active = false}
};
moq.Setup(x => x.FindAll()).Returns(list);
var service = new MyService(moq.Object);
var result = service.FindActiveCategories();
Assert.IsTrue(result.All(x=>x.Active));
}
And the test of course passed. But than I realized that I retreived all the Categories in my service method using FindAll - it was an obvious thing to correct, because I didn't want to load several thousands of categories to memory just to pull out only few of them. So I changed the implementation of FindActiveCategories method to this:
public List<Category> FindActiveCategories()
{
return _repo.FindByQuery(x => x.Active).ToList();
}
And my test failed this time. The problems is obvious - the test depended on the implementation details. I knew that the FindActiveCategories method uses FindAll method of the repository, so I wrote a setup for this method. After changing the implementation I have to change the implementation of the test method - this seems to be a problem. Of course I could've setup all the Find... methods but there are plenty of them in the repository and one can choose many of them, this also doesn't seem right approach for me. Not to mention TDD - if I was trying to write the test first, I wouldn't know what and how to mock the repository interface. My question is: what is a correct way to handle this kind of dependencies to be able to write implementation independent unit tests.
Despite the title of this question, the actual question here seems to be "should I need to change my test if my code implementation changes?"
The answer to that is that if the implementation is entirely contained within your code under test then 'no'. For example, if I have a method to multiply two values and I implement it the obvious way, I can write tests to prove that it works. Now if I change the implementation to do the calculation using a for loop and accumulating a total within the loop, all of my tests should pass with no changes.
The problem is that most of the code we write isn't like that: it depends on other things. If the code under test depends on other things we have two choices: do an integration test, or mock the dependency.
The integration test supplies the class under test with the real dependencies that it would be using when actually in use. This is the most valuable testing, since it is completely realistic. The answer here would also be 'no need to change the test if you change the implementation'. However, this is often impractical, since it exponentially increases the cost of writing and maintaining the tests.
Mocking requires you to specify how the dependency should behave, so by definition, your test must know what the code under test is going to use, and how. Therefore if you change the implementation, you should reasonably expect to have to change the test, so the answer would be 'yes'.
However, consider this point. The parts of your test which do not relate to mocking should not need to change. You aren't using the Arrange Act Assert pattern (which can help make tests more readable, particularly when mocking); but the Act and Assert parts, which would be the last two lines of your test, should not need to change. Maybe that will allow you to believe you're still doing TDD.
But don't lose sleep over it: there are other things which would benefit from your attention more. For example, change the implementation of your method to...
public List<Category> FindActiveCategories()
{
return new List<Category>();
}
... then the test will pass, even though the code won't do what you want (because the All in the assert returns true for an empty list).
Hope this was useful.
The following will work for the change made above.
[TestClass]
public class MyServiceShould {
[TestMethod]
public void FindActiveCategories_WhenCalled_ShouldReturnActiveCategories() {
//Arrange
var moq = new Mock<IRepository<Category>>();
var list = new List<Category> {
new Category {Active = true},
new Category {Active = false}
};
moq
.Setup(x => x.FindByQuery(It.IsAny<Predicate<Category>>()))
.Returns((Predicate<Category> predicate) => list.Where(x => predicate(x)));
var service = new MyService(moq.Object);
//Act
var result = service.FindActiveCategories();
//Assert
Assert.IsTrue(result.All(x => x.Active));
}
}
The mock takes the passed predicate and applies it to the fake collection in order to allow the test to be exercised to completion.
Reference Moq Quickstart to get a better understanding of how to use the mocking framework.

How to test methods where DBContext is created?

I don't have a lot of experience with unit testing. For example I have simple method in the application:
public void GetName()
{
UserRights rights = new UserRights(new DatabaseContext());
string test = rights.LookupNameByID("12345");
Console.WriteLine(test);
}
In this case I'm able to test all methods of UserRights class by passing mocked DatabaseContext, but how can I test GetName() method? What is the best practice? Where DatabaseContext should be created?
If you want to test the GetName method in a properly isolated way (i.e. a Unit Test) then you can't use new to create the UserRights instance in the method itself; because a test is really just another client of the code, therefore it can't (and shouldn't) know anything about how GetName works internally
So what this means is that for a proper Unit Test you must be able to replace all dependencies of a method with ones that the client fully controls - in the case, the code in the Unit Test is the client.
In your posted code, the client code has no control at all over UserRights nor DatabaseContext, so this is the first thing that has to change.
You need to rework your code so that the UserRights implementation can be supplied by the client. In fact once that's done, the problem about where DatabaseContext comes from is actually irrelevant for the Unit test because it doesn't care about how UserRights itself performs its tasks!
There are a number of ways of doing this; you can use Mocks or Stubs, you can use Constructor or Method injection, you could use a UserRights factory. Here is an example of using very simple stubs which IMHO is the best way to start and avoids having to learn a Mocking framework -- I personally would use Mocks for this but that's cos I am lazy :)
(code below assumes the class containing GetName is called "UserService", and uses xUnit framework; but MSTest will work just fine too)
Let's suppose you have control over the code of UserService so you can make the LookupNameByID method virtual (if you can't, then you may have to go the route if interfaces and mocks)
public class UserRights
{
public virtual LookupNameByID(string id)
{
//does whatever a UserRights does.
}
}
public class UserService
{
readonly UserRights _rights;
public UserService(UserRights rights)
{
_rights=rights; //null guard omitted for brevity
}
public string GetName(string id)
{
return _rights.LookupNameByID(id);
}
}
now in your unit test code suppose you create a sub-class of UserRights like this:
public class ExplodingUserRights: UserRights
{
public override string LookupNameByID(string id)
{
throw new Exception("BOOM!");
}
}
Now you can write a test to see how GetName reacts when something bad happens:
[Fact]
public void LookupNameByID_WhenUserRightsThrowsException_DoesNotReThrow()
{
//this test will fail if an exception is thrown, thus proving that GetName doesn't handle exceptions correctly.
var sut = new UserService(new ExplodingUserRights()); <-Look, no DatabaseContext!
sut.GetName("12345");
}
and one for when good things happen:
public class HappyUserRights: UserRights
{
public override string LookupNameByID(string id)
{
return "yay!";
}
}
[Fact]
public void LookupNameByID_ReturnsResultOfUserRightsCall()
{
//this test will fail if an exception is thrown, thus proving that GetName doesn't handle exceptions correctly.
var sut = new UserService(new HappyUserRights());
var actual = sut.GetName("12345");
Assert.Equal("yay!",actual);
}
and so on. Note that we never went anywhere near DatabaseContext, because that's a problem you only have to solve when you unit test the UserRights class itself. (and at that point I would probably recommend using Jeroen's advice from his linked article,and do an integration test, unless setup of a database for each test is something you can't or won't do, in which case you need to use interfaces and mocks)
Hope that helps.
Separating your codes reliance on DB Context is something you will want to investigate, this can be accomplished using the Repository pattern. Since you're passing the DB Context into your objects constructor, in this case UserRights, you can pretty easily change your code to take in an Interface (or simply add an overloaded contructor to the class that accepts an interface, then call that in your unit tests, preserving any existing code). There are lots of ways to get this done, a quick Google search yielded the following article:
http://romiller.com/2012/02/14/testing-with-a-fake-dbcontext/
http://www.codeproject.com/Articles/207820/The-Repository-Pattern-with-EF-code-first-Dependen
Once your class can accept an interface rather than (or as an alternative to) the strongly typed DB Context object you can use a Mock framework to assist with testing. Take a look at Moq for examples on how to use these in your unit tests https://github.com/Moq/moq4/wiki/Quickstart
Be Aware: Moq can become difficult to work with when your tests require data that is related via foreign keys, the syntax can be complicated to get your head around. One thing to watch out for is the temptation to make changes to your code just to make a unit test easier to set up, while there may be value in making this change it also may indicate that you need to re-think your unit test rather than violate your applications architecture and/or design patterns

How can I avoid adding getters to facilitate unit testing?

After reading a blog post mentioning how it seems wrong to expose a public getter just to facilitate testing, I couldn't find any concrete examples of better practices.
Suppose we have this simple example:
public class ProductNameList
{
private IList<string> _products;
public void AddProductName(string productName)
{
_products.Add(productName);
}
}
Let's say for object-oriented design reasons, I have no need to publicly expose the list of products. How then can I test whether AddProductName() did its job? (Maybe it added the product twice, or not at all.)
One solution is to expose a read-only version of _products where I can test whether it has only one product name -- the one I passed to AddProductName().
The blog post I mentioned earlier says it's more about interaction (i.e., did the product name get added) rather than state. However, state is exactly what I'm checking. I already know AddProductName() has been called -- I want to test whether the object's state is correct once that method has done its work.
Disclaimer: Although this question is similar to
Balancing Design Principles: Unit Testing, (1) the language is different (C# instead of Java), (2) this question has sample code, and (3) I don't feel the question was adequately answered (i.e., code would have helped demonstrate the concept).
Unit tests should test the public API.
If you have "no need to publicly expose the list of products", then why would you care whether AddProductName did its job? What possible difference would it make if the list is entirely private and never, ever affected anything else?
Find out what affect AddProductName has on the state that can be detected using the API, and test that.
Very similar question here: Domain Model (Exposing Public Properties)
You could make your accessors protected so you can mock or you could use internal so that you can access the property in a test but that IMO would be wrong as you have suggested.
I think sometimes we get so caught up in wanting to make sure that every little thing in our code is tested. Sometime we need to take a step back and ask why are we storing this value, and what is its purpose? Then instead of testing that the value gets set we can then start testing that the behaviour of the component is correct.
EDIT
One thing you can do in your scenario is to have a bastard constructor where you inject an IList and then you test that you have added a product:
public class ProductNameList
{
private IList<string> _products;
internal ProductNameList(IList<string> products)
{
_products = products;
}
...
}
You would then test it like this:
[Test]
public void FooTest()
{
var productList = new List<string>();
var productNameList = new ProductNameList(productList);
productNameList.AddProductName("Foo");
Assert.IsTrue(productList[0] == "Foo");
}
You will need to remember to make internals visable to your test assembly.
Make _products protected instead of private. In your mock, you can add an accessor.
To test if AddProductName() did it's job, instead of using a public getter for _ProductNames, make a call to GetProductNames() - or the equivalent that's defined in your API. Such a function may not necessarily be in the same class.
Now, if your API does not expose any way to get information about product names, then AddProductName() has no observable side effects (In which case, it is a meaningless function).
If AddProductName() does have side effects, but they are indirect - say, a method in ProductList that writes the list of product names to a file, then ProductList should be split into two classes - one that manages the list, and the other that calls it's Add and Get API, and performs side effects.

How to handle setting up complex unit test and have them only test the unit

I have a method that takes 5 parameters. This method is used to take a bunch of gathered information and send it to my server.
I am writing a unit test for this method, but I am hitting a bit of a snag. Several of the parameters are Lists<> of classes that take some doing to setup correctly. I have methods that set them up correctly in other units (production code units). But if I call those then I am kind of breaking the whole idea of a unit test (to only hit one "unit").
So.... what do I do? Do I duplicate the code that sets up these objects in my Test Project (in a helper method) or do I start calling production code to setup these objects?
Here is hypothetical example to try and make this clearer:
File: UserDemographics.cs
class UserDemographics
{
// A bunch of user demographic here
// and values that get set as a user gets added to a group.
}
File: UserGroups.cs
class UserGroups
{
// A bunch of variables that change based on
// the demographics of the users put into them.
public AddUserDemographicsToGroup(UserDemographcis userDemographics)
{}
}
File: UserSetupEvent.cs
class UserSetupEvent
{
// An event to record the registering of a user
// Is highly dependant on UserDemographics and semi dependant on UserGroups
public SetupUserEvent(List<UserDemographics> userDemographics,
List<UserGroup> userGroups)
{}
}
file: Communications.cs
class Communications
{
public SendUserInfoToServer(SendingEvent sendingEvent,
List<UserDemographics> userDemographics,
List<UserGroup> userGroups,
List<UserSetupEvent> userSetupEvents)
{}
}
So the question is: To unit test SendUserInfoToServer should I duplicate SetupUserEvent and AddUserDemographicsToGroup in my test project, or should I just call them to help me setup some "real" parameters?
You need test duplicates.
You're correct that unit tests should not call out to other methods, so you need to "fake" the dependencies. This can be done one of two ways:
Manually written test duplicates
Mocking
Test duplicates allow you to isolate your method under test from its dependencies.
I use Moq for mocking. Your unit test should send in "dummy" parameter values, or statically defined values you can use to test control flow:
public class MyTestObject
{
public List<Thingie> GetTestThingies()
{
yield return new Thingie() {id = 1};
yield return new Thingie() {id = 2};
yield return new Thingie() {id = 3};
}
}
If the method calls out to any other classes/methods, use mocks (aka "fakes"). Mocks are dynamically-generated objects based on virtual methods or interfaces:
Mock<IRepository> repMock = new Mock<IRepository>();
MyPage obj = new MyPage() //let's pretend this is ASP.NET
obj.IRepository = repMock.Object;
repMock.Setup(r => r.FindById(1)).Returns(MyTestObject.GetThingies().First());
var thingie = MyPage.GetThingie(1);
The Mock object above uses the Setup method to return the same result for the call defined in the r => r.FindById(1) lambda. This is called an expecation. This allows you to test only the code in your method, without actually calling out to any dependent classes.
Once you've set up your test this way, you can use Moq's features to confirm that everything happened the way it was supposed to:
//did we get the instance we expected?
Assert.AreEqual(thingie.Id, MyTestObject.GetThingies().First().Id);
//was a method called?
repMock.Verify(r => r.FindById(1));
The Verify method allows you to test whether a method was called. Together, these facilities allow you focus your unit tests on a single method at a time.
Sounds like your units are too tightly coupled (at least from a quick view at your problem). What makes me curious is for instance the fact that your UserGroups takes a UserDemographics and your UserSetupEvent takes a list of UserGroup including a list of UserDemographics (again). Shouldn't the List<UserGroup> already include the ÙserDemographics passed in it's constructor or am I misunderstanding it?
Somehow it seems like a design problem of your class model which in turn makes it difficult to unit test. Difficult setup procedures are a code smell indicating high coupling :)
Bringing in interfaces is what I would prefer. Then you can mock the used classes and you don't have to duplicate code (which violates the Don't Repeat Yourself principle) and you don't have to use the original implementations in the unit tests for the Communications class.
You should use mock objects, basically your unit test should probably just generate some fake data that looks like real data instead of calling into the real code, this way you can isolate the test and have predictable test results.
You can make use of a tool called NBuilder to generate test data. It has a very good fluent interface and is very easy to use. If your tests need to build lists this works even better. You can read more about it here.

Unit testing, mocking - simple case: Service - Repository

Consider a following chunk of service:
public class ProductService : IProductService {
private IProductRepository _productRepository;
// Some initlization stuff
public Product GetProduct(int id) {
try {
return _productRepository.GetProduct(id);
} catch (Exception e) {
// log, wrap then throw
}
}
}
Let's consider a simple unit test:
[Test]
public void GetProduct_return_the_same_product_as_getProduct_on_productRepository() {
var product = EntityGenerator.Product();
_productRepositoryMock.Setup(pr => pr.GetProduct(product.Id)).Returns(product);
Product returnedProduct = _productService.GetProduct(product.Id);
Assert.AreEqual(product, returnedProduct);
_productRepositoryMock.VerifyAll();
}
At first it seems that this test is ok. But let's change our service method a little bit:
public Product GetProduct(int id) {
try {
var product = _productRepository.GetProduct(id);
product.Owner = "totallyDifferentOwner";
return product;
} catch (Exception e) {
// log, wrap then throw
}
}
How to rewrite a given test that it'd pass with the first service method and fail with a second one?
How do you handle this kind of simple scenarios?
HINT 1: A given test is bad coz product and returnedProduct is actually the same reference.
HINT 2: Implementing equality members (object.equals) is not the solution.
HINT 3: As for now, I create a clone of the Product instance (expectedProduct) with AutoMapper - but I don't like this solution.
HINT 4: I'm not testing that the SUT does NOT do sth. I'm trying to test that SUT DOES return the same object as it is returned from repository.
Personally, I wouldn't care about this. The test should make sure that the code is doing what you intend. It's very hard to test what code is not doing, I wouldn't bother in this case.
The test actually should just look like this:
[Test]
public void GetProduct_GetsProductFromRepository()
{
var product = EntityGenerator.Product();
_productRepositoryMock
.Setup(pr => pr.GetProduct(product.Id))
.Returns(product);
Product returnedProduct = _productService.GetProduct(product.Id);
Assert.AreSame(product, returnedProduct);
}
I mean, it's one line of code you are testing.
Why don't you mock the product as well as the productRepository?
If you mock the product using a strict mock, you will get a failure when the repository touches your product.
If this is a completely ridiculous idea, can you please explain why? Honestly, I'd like to learn.
One way of thinking of unit tests is as coded specifications. When you use the EntityGenerator to produce instances both for the Test and for the actual service, your test can be seen to express the requirement
The Service uses the EntityGenerator to produce Product instances.
This is what your test verifies. It's underspecified because it doesn't mention if modifications are allowed or not. If we say
The Service uses the EntityGenerator to produce Product instances, which cannot be modified.
Then we get a hint as to the test changes needed to capture the error:
var product = EntityGenerator.Product();
// [ Change ]
var originalOwner = product.Owner;
// assuming owner is an immutable value object, like String
// [...] - record other properties as well.
Product returnedProduct = _productService.GetProduct(product.Id);
Assert.AreEqual(product, returnedProduct);
// [ Change ] verify the product is equivalent to the original spec
Assert.AreEqual(originalOwner, returnedProduct.Owner);
// [...] - test other properties as well
(The change is that we retrieve the owner from the freshly created Product and check the owner from the Product returned from the service.)
This embodies the fact that the Owner and other product properties must equal the the original value from the generator. This may seem like I'm stating the obvious, since the code is pretty trivial, but it runs quite deep if you think in terms of requirement specifications.
I often "test my tests" by stipulating "if I change this line of code, tweak a critical constant or two, or inject a few code burps (e.g. changing != to ==), which test will capture the error?" Doing it for real finds if there is a test that captures the problem. Sometimes not, in which case it's time to look at the requirements implicit in the tests, and see how we can tighten them up. In projects with no real requirements capture/analysis this can be a useful tool to toughen up tests so they fail when unexpected changes occur.
Of course, you have to be pragmatic. You can't reasonably expect to handle all changes - some will simply be absurd and the program will crash. But logical changes like the Owner change are good candidates for test strengthening.
By dragging talk of requirements into a simple coding fix, some may think I've gone off the deep end, but thorough requirements help produce thorough tests, and if you have no requirements, then you need to work doubly hard to make sure your tests are thorough, since you're implicitly doing requirements capture as you write the tests.
EDIT: I'm answering this from within the contraints set in the question. Given a free choice, I would suggest not using the EntityGenerator to create Product test instances, and instead create them "by hand" and use an equality comparison. Or more direct, compare the fields of the returned Product to specific (hard-coded) values in the test, again, without using the EntityGenerator in the test.
Q1: Don't make changes to code then write a test. Write a test first for the expected behavior. Then you can do whatever you want to the SUT.
Q2: You don't make the changes in your Product Gateway to change the owner of the product. You make the change in your model.
But if you insist, then listen to your tests. They are telling you that you have the possibility for products to be pulled from the gateway that have the incorrect owners. Oops, Looks like a business rule. Should be tested for in the model.
Also your using a mock. Why are you testing an implementation detail? The gateway only cares that the _productRepository.GetProduct(id) returns a product. Not what the product is.
If you test in this manner you will be creating fragile tests. What if product changes further. Now you have failing tests all over the place.
Your consumers of product (MODEL) are the only ones that care about the implementation of Product.
So your gateway test should look like this:
[Test]
public void GetProduct_return_the_same_product_as_getProduct_on_productRepository() {
var product = EntityGenerator.Product();
_productRepositoryMock.Setup(pr => pr.GetProduct(product.Id)).Returns(product);
_productService.GetProduct(product.Id);
_productRepositoryMock.VerifyAll();
}
Don't put business logic where it doesn't belong! And it's corollary is don't test for business logic where there should be none.
If you really want to guarantee that the service method doesn't change the attributes of your products, you have two options:
Define the expected product attributes in your test and assert that the resulting product matches these values. (This appears to be what you're doing now by cloning the object.)
Mock the product and specify expectations to verify that the service method does not change its attributes.
This is how I'd do the latter with NMock:
// If you're not a purist, go ahead and verify all the attributes in a single
// test - Get_Product_Does_Not_Modify_The_Product_Returned_By_The_Repository
[Test]
public Get_Product_Does_Not_Modify_Owner() {
Product mockProduct = mockery.NewMock<Product>(MockStyle.Transparent);
Stub.On(_productRepositoryMock)
.Method("GetProduct")
.Will(Return.Value(mockProduct);
Expect.Never
.On(mockProduct)
.SetProperty("Owner");
_productService.GetProduct(0);
mockery.VerifyAllExpectationsHaveBeenMet();
}
My previous answer stands, though it assumes the members of the Product class that you care about are public and virtual. This is not likely if the class is a POCO / DTO.
What you're looking for might be rephrased as a way to do comparison of the values (not instance) of the object.
One way to compare to see if they match when serialized. I did this recently for some code... Was replacing a long parameter list with a parameterized object. The code is crufty, I don't want to refactor it though as its going away soon anyhow. So I just do this serialization comparison as a quick way to see if they have the same value.
I wrote some utility functions... Assert2.IsSameValue(expected,actual) which functions like NUnit's Assert.AreEqual(), except it serializes via JSON before comparing. Likewise, It2.IsSameSerialized() can be used to describe parameters passed to mocked calls in a manner similar to Moq.It.Is().
public class Assert2
{
public static void IsSameValue(object expectedValue, object actualValue) {
JavaScriptSerializer serializer = new JavaScriptSerializer();
var expectedJSON = serializer.Serialize(expectedValue);
var actualJSON = serializer.Serialize(actualValue);
Assert.AreEqual(expectedJSON, actualJSON);
}
}
public static class It2
{
public static T IsSameSerialized<T>(T expectedRecord) {
JavaScriptSerializer serializer = new JavaScriptSerializer();
string expectedJSON = serializer.Serialize(expectedRecord);
return Match<T>.Create(delegate(T actual) {
string actualJSON = serializer.Serialize(actual);
return expectedJSON == actualJSON;
});
}
}
Well, one way is to pass around a mock of product rather than the actual product. Verify nothing to affect the product by making it strict. (I assume you are using Moq, it looks like you are)
[Test]
public void GetProduct_return_the_same_product_as_getProduct_on_productRepository() {
var product = new Mock<EntityGenerator.Product>(MockBehavior.Strict);
_productRepositoryMock.Setup(pr => pr.GetProduct(product.Id)).Returns(product);
Product returnedProduct = _productService.GetProduct(product.Id);
Assert.AreEqual(product, returnedProduct);
_productRepositoryMock.VerifyAll();
product.VerifyAll();
}
That said, I'm not sure you should be doing this. The test is doing to much, and might indicate there is another requirement somewhere. Find that requirement and create a second test. It might be that you just want to stop yourself from doing something stupid. I don't think that scales, because there are so many stupid things you can do. Trying to test each would take too long.
I'm not sure, if the unit test should care about "what given method does not". There are zillion steps which are possible. In strict the test "GetProduct(id) return the same product as getProduct(id) on productRepository" is correct with or without the line product.Owner = "totallyDifferentOwner".
However you can create a test (if is required) "GetProduct(id) return product with same content as getProduct(id) on productRepository" where you can create a (propably deep) clone of one product instance and then you should compare contents of the two objects (so no object.Equals or object.ReferenceEquals).
The unit tests are not guarantee for 100% bug free and correct behaviour.
You can return an interface to product instead of a concrete Product.
Such as
public IProduct GetProduct(int id)
{
return _productRepository.GetProduct(id);
}
And then verify the Owner property was not set:
Dep<IProduct>().AssertWasNotCalled(p => p.Owner = Arg.Is.Anything);
If you care about all the properties and or methods, then there is probably a pre-existing way with Rhino. Otherwise you can make an extension method that probably uses reflection such as:
Dep<IProduct>().AssertNoPropertyOrMethodWasCalled()
Our behaviour specifications are like so:
[Specification]
public class When_product_service_has_get_product_called_with_any_id
: ProductServiceSpecification
{
private int _productId;
private IProduct _actualProduct;
[It]
public void Should_return_the_expected_product()
{
this._actualProduct.Should().Be.EqualTo(Dep<IProduct>());
}
[It]
public void Should_not_have_the_product_modified()
{
Dep<IProduct>().AssertWasNotCalled(p => p.Owner = Arg<string>.Is.Anything);
// or write your own extension method:
// Dep<IProduct>().AssertNoPropertyOrMethodWasCalled();
}
public override void GivenThat()
{
var randomGenerator = new RandomGenerator();
this._productId = randomGenerator.Generate<int>();
Stub<IProductRepository, IProduct>(r => r.GetProduct(this._productId));
}
public override void WhenIRun()
{
this._actualProduct = Sut.GetProduct(this._productId);
}
}
Enjoy.
If all consumers of ProductService.GetProduct() expect the same result as if they had asked it from the ProductRepository, why don't they just call ProductRepository.GetProduct() itself ?
It seems you have an unwanted Middle Man here.
There's not much value added to ProductService.GetProduct(). Dump it and have the client objects call ProductRepository.GetProduct() directly. Put the error handling and logging into ProductRepository.GetProduct() or the consumer code (possibly via AOP).
No more Middle Man, no more discrepancy problem, no more need to test for that discrepancy.
Let me state the problem as I see it.
You have a method and a test method. The test method validates the original method.
You change the system under test by altering the data. What you want to see is that the same unit test fails.
So in effect you're creating a test that verifies that the data in the data source matches the data in your fetched object AFTER the service layer returns it. That probably falls under the class of "integration test."
You don't have many good options in this case. Ultimately, you want to know that every property is the same as some passed-in property value. So you're forced to test each property independently. You could do this with reflection, but that won't work well for nested collections.
I think the real question is: why test your service model for the correctness of your data layer, and why write code in your service model just to break the test? Are you concerned that you or other users might set objects to invalid states in your service layer? In that case you should change your contract so that the Product.Owner is readonly.
You'd be better off writing a test against your data layer to ensure that it fetches data correctly, then use unit tests to check the business logic in your service layer. If you're interested in more details about this approach reply in the comments.
Having look on all 4 hints provided it seems that you want to make an object immutable at runtime. C# language does no support that. It is possible only with refactoring the Product class itself. For refactoring you can take IReadonlyProduct approach and protect all setters from being called. This however still allows modification of elements of containers like List<> being returned by getters. ReadOnly collection won't help either. Only WPF lets you change immutability at runtime with Freezable class.
So I see the only proper way to make sure objects have same contents is by comparing them. Probably the easiest way would be to add [Serializable] attribute to all involved entities and do the serialization-with-comparison as suggested by Frank Schwieterman.

Categories

Resources