Unit testing, mocking - simple case: Service - Repository - c#

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.

Related

Can't stub a ReadOnly property twice?

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.

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.

Constructive criticism on this class

I've just reviewed some code that looked like this before
public class ProductChecker
{
// some std stuff
public ProductChecker(int AccountNumber)
{
var account = new AccountPersonalDetails(AccountNumber);
//Get some info from account and populate class fields
}
public bool ProductACriteriaPassed()
{
//return some criteria based on stuff in account class
//but now accessible in private fields
}
}
There has now been some extra criteria added which needs data not in the AccountPersonalDetails class
the new code looks like this
public class ProductChecker
{
// some std stuff
public ProductChecker(int AccountNumber)
{
var account = new AccountPersonalDetails(AccountNumber);
var otherinfo = getOtherInfo(AccountNumber)
//Get some info from account and populate class fields
}
public bool ProductACriteriaPassed()
{
//return some criteria based on stuff in account class
// but now accessible in private fields and other info
}
public otherinfo getOtherInfo(int AccountNumber)
{
//DIRECT CALL TO DB TO GET OTHERINFO
}
}
I'm bothered by the db part but can people spell out to me why this is wrong? Or is it?
In a layered view of your system, it looks like ProductChecker belongs to the business rules / business logic layer(s), so it shouldn't be "contaminated" with either user interaction functionality (that belongs in the layer(s) above) or -- and that's germane to your case -- storage functionality (that belongs in the layer(s) below).
The "other info" should be encapsulated in its own class for the storage layers, and that class should be the one handling persist/retrieve functionality (just like I imagine AccountPersonalDetails is doing for its own stuff). Whether the "personal details" and "other info" are best kept as separate classes or joined into one I can't tell from the info presented, but the option should be critically considered and carefully weighed.
The rule of thumb of keeping layers separate may feel rigid at times, and it's often tempting to shortcut it to add a feature by miscegenation of the layers -- but to keep your system maintainable and clean as it grows, I do almost invariably argue for layer separation whenever such a design issue arises. In OOP terms, it speaks to "strong cohesion but weak coupling"; but in a sense it's more fundamental than OOP since it also applies to other programming paradigms, and mixes thereof!-)
It seems like the extra data grabbed in getOtherInfo should be encapsulated as part of the AccountPersonalDetails class, and thus already part of your account variable in the constructor when you create a new AccountPersonalDetails object. You pass in AccountNumber to both, so why not make AccountPersonalDetails gather all the info you need? Then you won't have to tack on extra stuff externally, as you're doing now.
It definitely looks like there might be something going haywire with the design of the class...but it's hard to tell without knowing the complete architecture of the application.
First of all, if the OtherInfo object pertains to the Account rather than the Product you're checking on...it's introducing responsibilities to your class that shouldn't be there.
Second of all, if you have a Data Access layer...then the ProductChecker class should be using the Data Access layer to retrieve data from the database rather than making direct calls in to retrieve the data it needs.
Third of all, I'm not sure that the GetOtherInfo method needs to be public. It looks like something that should only be used internally to your class (if, in fact, it actually belongs there to begin with). In that case, you also shouldn't need to pass around the accountId (you class should hold that somewhere already).
But...if OtherInfo pertains to the Product you're checking on AND you have no real Data Access layer then I can see how this might be a valid design.
Still, I'm on your side. I don't like it.
considering that an accountNumber was passed into the constructor you shouldn't have to pass it to another method like that.
A few points
The parameter names are pascal case, instead of camel (this maybe a mistake)
getOtherInfo() looks like it's a responsibility of AccountPersonalDetails and so should be in that class
You may want to use a Façade class or Repository pattern to retrieve your AccountPersonalDetails instead of using a constructor
getOtherInfo() may also be relevant for this refactor, so the database logic isn't embedded inside the domain object, but in a service class (the Façade/Repository)
ProductACriteriaPassed() is in the right place
I would recommend this:
public class AccountPersonalDetails
{
public OtherInfo OtherInfo { get; private set; }
}
public class ProductChecker
{
public ProductChecker(AccountPersonalDetails) {}
}
// and here's the important piece
public class EitherServiceOrRepository
{
public static AccountPersonalDetails GetAccountDetailsByNumber(int accountNumber)
{
// access db here
}
// you may also feel like a bit more convinience via helpers
// this may be inside ProductCheckerService, though
public static ProductChecker GetProductChecker(int accountNumber)
{
return new ProductChecker(GetAccountDetailsByNumber(accountNumber));
}
}
I'm not expert in Domain-Driven Design but I believe this is what DDD is about. You keep your logic clean of DB concerns, moving this to external services/repositories. Will be glad if somebody correct me if I'm wrong.
Whats good. It looks like you have a productChecker with a nice clear purpose. Check products. You'd refactor or alter this because your have a need to. If you don't need to, you wouldn't. Here's what I would probably do.
It "feels" clunky to create a new instance of the class for each account number. A constructor argument should be something required for the class to behave correctly. Its a parameter of the class, not a dependency. It leads to the tempation to do a lot of work in the constructor. Usage of the class should look like this:
result = new ProductChecker().ProductACriteriaPassed(accountNumber)
Which I'd quickly rename to indicate it does work.
result = new ProductChecker().PassesProductACriteria(accountNumber)
A few others have mentioned that you may want to split out the database logic. You'd want to do this if you want unit tests that are fast. Most programs want unit tests (unless you are just playing around), and they are nicer if they are fast. They are fast when you can get the database out of the way.
Let's make a dummy object representing results of the database, and pass it to a method that determines whether the product passes. If not for testibility, this would be a private. Testability wins. Suppose I want to verify a rule such as "the product must be green if the account number is prime." This approach to unit testing works great without fancy infrastructure.
// Maybe this is just a number of items.
DataRequiredToEvaluateProduct data = // Fill in data
// Yes, the next method call could be static.
result = new ProductChecker().CheckCriteria(accountNumber, data)
// Assert result
Now we need to connect the database. The database is a dependency, its required for the class to behave correctly. It should be provided in the constructor.
public class ProductRepository {} // Define data access here.
// Use the ProductChecker as follows.
result = new ProductChecker(new ProductRepository()).CheckCriteria(accountNumber)
If the constructor gets annoyingly lengthy (it probably has to read a config file to find the database), create a factory to sort it out for you.
result = ProductCheckerFactory().GimmeProductChecker().CheckCriteria(accountNumber)
So far, I haven't used any infrastructure code. Typically, we'd make the above easier and prettier with mocks and dependency injection (I use rhinomocks and autofac). I won't go into that. That is only easier if you already have it in place.

Why does my object mocking fail?

I am using the Moq and can't seem to get my unit test to pass on what appears to be a simple mocking scenario.
Product p = new Product();
var rep = new Mock<IProductRepository>();
rep.Expect(x => x.GetProductById(1)).Returns(p);
p = rep.Object.GetProductById(1);
Assert.AreEqual(1, p.ProductId); //Assert.AreEqual failed. Expected:<1>. Actual:<0>.
Any pointers on what I'm doing wrong? My Unit test reports:-
Assert.AreEqual failed. Expected:<1>. Actual:<0>.
I think you are missing the point of how to use mock objects in tests...
What you are doing is mocking a ProductRepository object while simultaneously testing it. That doesn't make much sense; you should not mock the object you're testing.
Let's say you have a class you want to test, ProductService, and it depends on another class, IProductRepository. When you test the ProductService, you will want to mock the dependency, IProductRepository. This allows you completely control the interaction between the class under test and its (mocked) dependency.
As you do so, your assertions will be based on what you expect the class under test, ProductService, to do. For instance, if you call the ProductService using something like productService.GetProductById(1), you will expect the ProductService object to call its IProductRepository method with the correct parameter exactly once: repository.GetProductById(1). You may also expect the ProductService to return the same object that the IProductRepository gave it. Regardless of what the repository does, that's the responsibility of the ProductService.
Having said that, your test may look something more like this:
//Arrange
int testId = 1;
var fakeProduct = new Product{ Id = testId };
var mockRepo = new Mock<IRepository>();
var productService = new ProductService(mockRepo);
mockRepo.Expect(repo => repo.GetProductById(testId)).Returns(fakeProduct);
//Act
Product returnedProduct = productService.GetProductById(testId);
//Assert
mockRepo.Verify(repo => repo.GetProductById(testId), TimesExactly(1));
Assert.AreEqual(returnedProduct.Id, fakeProduct.Id);
My syntax may be off, but hopefully the sample gets across a few points:
Don't mock the system under test
Mock the dependencies
Base your assertions on the responsibilities of the system under test, not the dependencies
You are creating an object, setting that object as the return value for a method, and then checking if the mock is altering the object, something that the mock is not intended to do You are basically doing this:
Product getProductById(Product p) { return p; }
...
Product p = new Product();
Assert.AreEqual(1, getProductById(p).ProductID );
when creating a new Product:
Product p = new Product();
i guess that the default ProductID is 0, so the sentence:
getProductById(p).ProductID
will obviously return 0.
I'm new to mock here too, but I don't see your point. What are you trying to test? The Product class, the ProductRepository, or interactions between them? That is the first thing to think about.
I'm looking at your code and it doesn't really look like you know what you're trying to achieve. Before writing any test, always ask the question: "What am I trying to prove, here?" The product you've created will be returned, but its ID will be the default value (0); this is expected behaviour, i.e. the mocking framework is working fine.
Test doubles (mocks, stubs, fakes, spies etc.) are used in tests to provide collaborators for the class under test. They feed interesting values into or receive calls from the class under test -- they are not the focus of the test.
Your test is currently asserting on a value returned by the test double itself. From what I can understand, either you're asking for help with an out of context code snippet (the snippet itself is just an example and not the test itself), or it is real test code that is pointless.
I've seen many a person tie themselves in knots with mocking frameworks. That's why, to begin with, I would recommend hand-writing your own test doubles. This helps you understand the interactions between the objects and form a clearer picture of what it is you wish to test. Again, this goes back to the question of "what am I trying to prove, here?".
Once you understand how to use hand-rolled test doubles to achieve a goal, you can graduate to mocking frameworks.
You're using the Product instance p once as 'the expected value' while you are setting up the expect - Returns (p)
and then using the same reference to store the return value of the actual call.
As for the Assert failure, does new Product() initialize its ProductId to 1. Seems like its being set to the default value of 0 - Hence the error.
I think the Mock framework is working.
I would second the view of Gishu re: the Product initialization. Unless the default behaviour of IProductRepository is to return a product referenced by the ProductId of '1', your test will fail.
And, may I add, this failure seems to be sensible behaviour. I think that you would like you ProductRepository to be empty upon initialization.
Not exactly missing the point, Mocking is not trivial.
In your case, you are having an IProductRepository that, I presume, is expected to hold Products. I assume that Products are not added to the ProductRepositort by default (per my earlier post), and I also assume that in order to reference a Product, it must have a productId (which by the way you really should mutate via a mutator).
If you would like to retrieve a Product from your ProductRepository, I think that you should add a Product to it through the mock framework (the moq site gives an example of registering and validating right at the top of the page), and ensure that the ProductRepostory either gives the Products added to it a default identifier (not recommended) or add an identifier to Product before adding it to the ProductRepository.

Categories

Resources