I have the following scenario:
public class CarManager
{
..
public long AddCar(Car car)
{
try
{
string username = _authorizationManager.GetUsername();
...
long id = _carAccessor.AddCar(username, car.Id, car.Name, ....);
if(id == 0)
{
throw new Exception("Car was not added");
}
return id;
} catch (Exception ex) {
throw new AddCarException(ex);
}
}
public List AddCars(List cars)
{
List ids = new List();
foreach(Car car in cars)
{
ids.Add(AddCar(car));
}
return ids;
}
}
I am mocking out _reportAccessor, _authorizationManager etc.
Now I want to unittest the CarManager class.
Should I have multiple tests for AddCar() such as
AddCarTest()
AddCarTestAuthorizationManagerException()
AddCarTestCarAccessorNoId()
AddCarTestCarAccessorException()
For AddCars() should I repeat all previous tests as AddCars() calls AddCar() - it seems like repeating oneself? Should I perhaps not be calling AddCar() from AddCars()? < p/>
Please help.
There are two issues here:
Unit tests should do more than test methods one at a time. They should be designed to prove that your class can do the job it was designed for when integrated with the rest of the system. So you should mock out the dependencies and then write a test for each way in which you class will actually be used. For each (non-trivial) class you write there will be scenarios that involve the client code calling methods in a particular pattern.
There is nothing wrong with AddCars calling AddCar. You should repeat tests for error handling but only when it serves a purpose. One of the unofficial rules of unit testing is 'test to the point of boredom' or (as I like to think of it) 'test till the fear goes away'. Otherwise you would be writing tests forever. So if you are confident a test will add no value them don't write it. You may be wrong of course, in which case you can come back later and add it in. You don't have to produce a perfect test first time round, just a firm basis on which you can build as you better understand what your class needs to do.
Unit Test should focus only to its corresponding class under testing. All attributes of class that are not of same type should be mocked.
Suppose you have a class (CarRegistry) that uses some kind of data access object (for example CarPlatesDAO) which loads/stores car plate numbers from Relational database.
When you are testing the CarRegistry you should not care about if CarPlateDAO performs correctly; Since our DAO has it's own unit test.
You just create mock that behaves like DAO and returns correct or wrong values according to expected behavior. You plug this mock DAO to your CarRegistry and test only the target class without caring if all aggregated classes are "green".
Mocking allows separation of testable classes and better focus on specific functionality.
When unittesting the AddCar class, create tests that will exercise every codepath. If _authorizationManager.GetUsername() can throw an exception, create a test where your mock for this object will throw. BTW: don't throw or catch instances of Exception, but derive a meaningful Exception class.
For the AddCars method, you definitely should call AddCar. But you might consider making AddCar virtual and override it just to test that it's called with all cars in the list.
Sometimes you'll have to change the class design for testability.
Should I have multiple tests for
AddCar() such as
AddCarTest()
AddCarTestAuthorizationManagerException()
AddCarTestCarAccessorNoId()
AddCarTestCarAccessorException()
Absolutely! This tells you valuable information
For AddCars() should I repeat all previous tests as AddCars() calls AddCar() - it seems
like repeating oneself? Should I perhaps not be calling AddCar() from AddCars()?
Calling AddCar from AddCars is a great idea, it avoids violating the DRY principle. Similarly, you should be repeating tests. Think of it this way - you already wrote tests for AddCar, so when testing AddCards you can assume AddCar does what it says on the tin.
Let's put it this way - imagine AddCar was in a different class. You would have no knowledge of an authorisation manager. Test AddCars without the knowledge of what AddCar has to do.
For AddCars, you need to test all normal boundary conditions (does an empty list work, etc.) You probably don't need to test the situation where AddCar throws an exception, as you're not attempting to catch it in AddCars.
Writing tests that explore every possible scenario within a method is good practice. That's how I unit test in my projects. Tests like AddCarTestAuthorizationManagerException(), AddCarTestCarAccessorNoId(), or AddCarTestCarAccessorException() get you thinking about all the different ways your code can fail which has led to me find new kinds of failures for a method I might have otherwise missed as well as improve the overall design of the class.
In a situation like AddCars() calling AddCar() I would mock the AddCar() method and count the number of times it's called by AddCars(). The mocking library I use allows me to create a mock of CarManager and mock only the AddCar() method but not AddCars(). Then your unit test can set how many times it expects AddCar() to be called which you would know from the size of the list of cars passed in.
Related
It is often told that writing unit tests one must test only a single class and mock all the collaborators. I am trying to learn TDD to make my code design better and now I am stuck with a situation where this rule should be broken. Or shouldn't it?
An example: class under test has a method that gets a Person, creates an Employee based on the Person and returns the Employee.
public class EmployeeManager {
private DataMiner dataMiner;
public Employee getCoolestEmployee() {
Person dankestPerson = dataMiner.getDankestPerson();
Employee employee = new Employee();
employee.setName(dankestPerson.getName() + "bug in my code");
return employee;
}
// ...
}
Should Employee be considered a collaborator? If not, why not? If yes, how do I properly test that 'Employee' is created correctly?
Here is the test I have in mind (using JUnit and Mockito):
#Test
public void coolestEmployeeShouldHaveDankestPersonsName() {
when(dataMinerMock.getDankestPerson()).thenReturn(dankPersonMock);
when(dankPersonMock.getName()).thenReturn("John Doe");
Employee coolestEmployee = employeeManager.getCoolestEmployee();
assertEquals("John Doe", coolestEmployee.getName());
}
As you see, I have to use coolestEmployee.getName() - method of the Employee class that is not under Test.
One possible solution that comes to mind is to extract the task of transforming Persons into Employees to a new method of Employee class, something like
public Employee createFromPerson(Person person);
Am I overthinking the problem? What is the correct way?
The goal of a unit test is to quickly and reliably determine whether a single system is broken. That doesn't mean you need to simulate the entire world around it, just that you should ensure that collaborators you use are fast, deterministic, and well-tested.
Data objects—POJOs and generated value objects in particular—tend to be stable and well-tested, with very few dependencies. Like other heavily-stateful objects, they also tend to be very tedious to mock, because mocking frameworks don't tend to have powerful control over state (e.g. getX should return n after setX(n)). Assuming Employee is a data object, it is likely a good candidate for actual use in unit tests, provided that any logic it contains is well-tested.
Other collaborators not to mock in general:
JRE classes and interfaces. (Never mock a List, for instance. It'll be impossible to read, and your test won't be any better for it.)
Deterministic third-party classes. (If any classes or methods change to be final, your mock will fail; besides, if you're using a stable version of the library, it's no spurious source of failure either.)
Stateful classes, just because mocks are much better at testing interactions than state. Consider a fake instead, or some other test double.
Fast and well-tested other classes that have few dependencies. If you have confidence in a system, and there's no hazard to your test's determinism or speed, there's no need to mock it.
What does that leave? Non-deterministic or slow service classes or wrappers that you've written, that are stateless or that change very little during your test, and that may have many collaborators of their own. In these cases, it would be hard to write a fast and deterministic test using the actual class, so it makes a lot of sense to use a test double—and it'd be very easy to create one using a mocking framework.
See also: Martin Fowler's article "Mocks Aren't Stubs", which talks about all sorts of test doubles along with their advantages and disadvantages.
Getters that only read a private field are usually not worth testing. By default, you can rely on them pretty safely in other tests. Therefore I wouldn't worry about using dankestPerson.getName() in a test for EmployeeManager.
There's nothing wrong with your test as far as testing goes. The design of the production code might be different - mocking dankestPerson probably means that it has an interface or abstract base class, which might be a sign of overengineering especially for a business entity. What I would do instead is just new up a Person, set its name to the expected value and set up dataMinerMock to return it.
Also, the use of "Manager" in a class name might indicate a lack of cohesion and too broad a range of responsibilities.
Consider you have the following method:
public Foo ParseMe(string filepath)
{
// break up filename
// validate filename & extension
// retrieve info from file if it's a certain type
// some other general things you could do, etc
var myInfo = GetFooInfo(filename);
// create new object based on this data returned AND data in this method
}
Currently I have unit tests for GetFooInfo, but I think I also need to build unit tests for ParseMe. In a situation like this where you have a two methods that return two different properties - and a change in either of them could break something - should unit tests be created for both to determine the output is as expected?
I like to err on the side of caution and be more wary about things breaking and ensuring that maintenance later on down the road is easier, but I feel very skeptical about adding very similar tests in the test project. Would this be bad practice or is there any way to do this more efficiently?
I'm marking this as language agnostic, but just in case it matters I am using C# and NUnit - Also, I saw a post similar to this in title only, but the question is different. Sorry if this has already been asked.
ParseMe looks sufficiently non-trivial to require a unit test. To answer your precise question, if "you have a two methods that return two different properties - and a change in either of them could break something" you should absolutely unit test them.
Even if the bulk of the work is in GetFooInfo, at minimum you should test that it's actually called. I know nothing about NUnit, but I know in other frameworks (like RSpec) you can write tests like GetFooInfo.should be_called(:once).
It is not a bad practice to test a method that is calling another method. In fact, it is a good practice. If you have a method calling another method, it is probably performing additional functionality, which should be tested.
If you find yourself unit testing a method that calls a method that is also being unit tested, then you are probably experiencing code reuse, which is a good thing.
I agree with #tsm - absolutely test both methods (assuming both are public).
This may be a smell that the method or class is doing too much - violating the Single Responsibility Principle. Consider doing an Extract Class refactoring and decoupling the two classes (possibly with Dependency Injection). That way you could test both pieces of functionality independently. (That said, I'd only do that if the functionality was sufficiently complex to warrant it. It's a judgment call.)
Here's an example in C#:
public interface IFooFileInfoProvider
{
FooInfo GetFooInfo(string filename);
}
public class Parser
{
private readonly IFooFileInfoProvider _fooFileInfoProvider;
public Parser(IFooFileInfoProvider fooFileInfoProvider)
{
// Add a null check
_fooFileInfoProvider = fooFileInfoProvider;
}
public Foo ParseMe(string filepath)
{
string filename = Path.GetFileName(filepath);
var myInfo = _fooFileInfoProvider.GetFooInfo(filename);
return new Foo(myInfo);
}
}
public class FooFileInfoProvider : IFooFileInfoProvider
{
public FooInfo GetFooInfo(string filename)
{
// Do I/O
return new FooInfo(); // parameters...
}
}
Many developers, me included, take a programming by contract approach. That requires you to consider each method as a black box. If the method delegates to another method to accomplish its task does not matter, when you are testing the method. But you should also test all large or complicated parts of your program as units. So whether you need to unit test the GetFooInfo depends on how complicated that method is.
Suppose I have several unit tests in a test class ([TestClass] in VSUnit in my case). I'm trying to test just one thing in each test (doesn't mean just one Assert though). Imagine there's one test (e.g. Test_MethodA() ) that tests a method used in other tests as well. I do not want to put an assert on this method in other tests that use it to avoid duplicity/maintainability issues so I have the assert in only this one test. Now when this test fails, all tests that depend on correct execution of that tested method fail as well. I want to be able to locate the problem faster so I want to be somehow pointed to Test_MethodA. It would e.g. help if I could make some of the tests in the test class execute in a particular order and when they fail I'd start looking for cause of the failure in the first failing test. Do you have any idea how to do this?
Edit: By suggesting that a solution would be to execute the tests in a particular order I have probably went too far and in the wrong direction. I don't care about the order of the tests. It's just that some of the tests will always fail if a prequisite isn't valid. E.g. I have a test class that tests a DAO class (ok, probably not a UNIT test, but there's logic in the database stored procedures that needs to be tested but that's not the point here I think). I need to insert some records into a table in order to test that a method responsible for retrieving the records (let's call it GetAll()) gets them all in the correct order e.g. I do the insert by using a method on the DAO class. Let's call it Insert(). I have tests in place that verify that the Insert() method works as expected. Now I want to test the GetAll() method. In order to get the database in a desired state I use the Insert() method. If Insert() doesn't work, most tests for GetAll() will fail. I'd prefer to mark the tests that can't pass because Insert() doesn't work as inconclusive rather than failed. It would ease finding the cause of the problem if I know which method/test to look into first.
You can't (and shouldn't) execute unit tests in a specific order. The underlying reason for this is to prevent Interacting Tests - I realize that your motivation for requesting such a feature is different, but that's the reason why unit test frameworks don't allow you to order tests. In fact, last time I checked, xUnit.net even randomizes the order.
One could argue that the fact that some of your tests depend on a different method call on the same class is a symptom of tight coupling, but that's not always the case (state machines come to mind).
However, if possible, consider using a Back Door instead of the other method in question.
If you can't do either that or decouple the interdependency (e.g. by making the first method virtual and using the Extract and Override technique), you will have to live with it.
Here's an example:
public class MyClass
{
public virtual void FirstMethod() { // do something... }
public void SecondMethod() {}
}
Since FirstMethod is virtual, you can derive from MyClass and override its behavior. You can also use a dynamic mock to do that for you. With Moq, it would look like this:
var sutStub = new Mock<MyClass>();
// by default, Moq overrides all virtual methods without calling base
// Now invoke both methods in sequence:
sutStub.Object.FirstMethod(); // overriden by Moq, so it does nothing
sutSutb.Object.SecondMethod();
I think I would indeed have the assertion on the method_A() result in every tests relying on its result, even if this introduces some duplication. Then I would use the assertion message to point to the method_A() failure.
assert("method_A() returned true", true, rc);
Perhaps will I end extracting the method_A() call and the assertion into an helper function to remove the duplication.
Now let's imagine method_A() queries an object and returns it, or NULL when no object is found. Then this assertion is a guard ; and it is necessary with languages suchas C, C++ that do not have NullPointerException.
I'm afraid you can't do this. The only solution is to redesign your code and break it up into smaller methods so that unit tests can call these one by one. Of course this isn't always desirable.
With Visual Studio you can order your tests: see here. But I'd like to advise you to stay away from this technique as much as possible: unit tests are meant to be run anywhere, anytime and in every order.
EDIT: why is this a problem for you? All failing tests point to the same method anyway...
If I was to write a mocking library, how would this work (in other words, how do "they work?)?
One of the things which I wonder is that you are always setting expectations so really you need to compare the expectation to what the method does at runtime, so I assume reflection (resolving types at runtime) is required.
Also, when using the term "mock object", is the object stubbed out or would it be an object with pre-set expectations?
When I think how I would write my own implementation of a framework/technique, like mock objects, I realise how much I really know (or don't know) and what I would trip up on: If the mock object is pre-programmed to return set expectations and you don't call the actual real object, then wouldn't the result always be the same? Eg:
[TestMethod, Isolated]
public void FakeReturnValueByMethodArgs()
{
var fake = Isolate.Fake.Instance<ClassToIsolate>();
// MethodReturnInt will return 10 when called with arguments 3, "abc"
Isolate.WhenCalled(()=> fake.MethodReturnInt(3, " abc")).WithExactArguments().WillReturn(10);
// MethodReturnInt will return 50 when called with arguments 3, "xyz"
Isolate.WhenCalled(()=> fake.MethodReturnInt(3, "xyz")).WithExactArguments().WillReturn(50);
Assert.AreEqual(10, fake.MethodReturnInt(3, "abc"));
Assert.AreEqual(50, fake.MethodReturnInt(3, "xyz"));
}
Wouldn't this always return true?
The idea with mocking frameworks is to mock out dependencies, and not the actual classes under test. For your example, your test will always return true, because really you're only testing the mocking framework and not your actual code!
A real world mock would look more like this:
[TestMethod, Isolated]
public void FakeReturnValueByMethodArgs() {
var fake = Isolate.Fake.Instance<DependencyClass>();
// MethodReturnInt will return 10 when called with arguments 3, "abc"
Isolate.WhenCalled(()=> fake.MethodReturnInt(3, "abc")).WithExactArguments().WillReturn(10);
var testClass = new TestClass(fake);
testClass.RunMethod();
// Verify that the setup methods were execute in RunMethod()
// Not familiar with TypeMock's actual method to do this...
IsolatorExtensions.VerifyInstanceWasCalled(fake);
// Or assert on values
Assert.AreEqual(10, testClass.AProperty);
}
Notice how the mock is passed into the TestClass and a method run on it.
You can read The Purpose of Mocking to get a better idea of how mocking works.
Update: Explanation why you're testing only the mocking framework:
What you've done is create a method MethodReturnInt with the mocking framework using Isolate.WhenCalled(). When you call MethodRecturnInt in the Assert, the code will run the delegate () => fake.MethodReturnInt() and return 10. The mocking framework is effectively creating a method (albeit dynamically) that would look something like this:
public void MethodReturnInt(int value, string value2) {
Assert.Equal(3, value);
Assert.Equal("abc", value2);
return 10;
}
It's a bit more complicated than that, but this is the general idea. Since you never run any code other than the creation of 2 methods and then asserts on those two methods, you're not testing your own code and therefore only testing the mocking framework.
Yes, it will always return true. Mock objects should be used when the class under test requires another class implementation that you don't want to involve in the test run. This is most useful when it's a class that uses interfaces with multiple implementations, or there are complex/expensive/external services that you don't want to set up.
In the above code, you're mocking the class that you're "testing".
Another way of thinking about it is that the mock behaviours you record are black-box (implementation) assertions, where Assert.* are white-box (api) assertions.
You have the right idea. You will often find that they have a couple of modes of operation. If you're worried about your method not getting called or it not getting called in the right order there is quite often a 'strict' mode that causes the mock framework to throw an exception if the method isn't called by the end of the test, or is called with the wrong parameters etc.
Most of the frameworks have thought of those sorts of issues so you just need to find out how to configure it for your scenario.
One way to look at how mock system work is just look at times when you need an object but you don't want to use the real class but instead want it to give you some specific kind of data that it wouldn't (or won't do so reliably). So if you see:
Assert.IsTrue(myLogic.IsNoon(time))
you can see how the assert would want the time object to always be noon. . . well you can't do that with a real object reliably. So you need a stand-in. You can make a fake class just for the test, but that's sort of heavy. Mock frameworks are a shortcut.
Example
I have a repository class (DAL):
public class MyRepository : IMyRepository
{
public void Delete(int itemId)
{
// creates a concrete EF context class
// deletes the object by calling context.DeleteObject()
}
// other methods
}
I also have a service class (BLL):
public class MyService
{
private IMyRepository localRepository;
public MyService(IMyRepository instance)
{
this.localRepository = instance;
}
public void Delete(int itemId)
{
instance.Delete(itemId);
}
// other methods
}
Creating a unit test for MyRepository would take much more time than implementing it, because I would have to mock Entity Framework context.
But creating a unit test for MyService seems nonsense, because it only calls into Repository. All I could check is to verify if it did actually call repository Delete method.
Question
How would you suggest to unit test these pair of Delete methods. Both? One? None? And what would you test?
Yes, I would definitely write a unit test for the Service Layer. The reason for this is because, you're not just testing that your implementation works now, but you're also testing that it will continue to work in the future.
This is a vital concept to understand. If someone comes along later on and changes your ServiceLayer, and there's no unit test, how can you verify that the functionality continues to work?
I would also write tests for your DAL, but I would put those in a separate assembly called DataTests or something. The purpose here is to isolate your concerns across assemblies. Unit Tests shouldn't be concerned with your DAL, really.
Yes, both.
IMyRepository mock = ...;
// create Delete(int) expectation
MyService service = new MyService(mock);
service.Delete(100);
// Verify expectations
Your Delete method right now might only call the Delete method on the repository, but that doesn't mean it always will. You want to have unit tests for this partly to verify it behaves correctly and partly as way of defining your specifications of how the repository is to work.
You also aught to have a test that verifies that the constructor will throw an exception if the repository is null. You might also have other validation to do here in this method such as non-negative ID's, or non-zero id. Maybe that doesn't happen here, make it part of the specifications by creating tests that verify the expected behaviors.
They seem trivial but I can all but guarantee it will change one day and your expectation and specifications may not be verified.
Create the test for the Service. Currently all it does is to call into the Repository Delete method; however, you shouldn't care about that. What if later something happens and the functionality becomes much more complicated? Don't you want to have unit test code that will assure you that the functionality is still working as expected?
If you're exposing your Delete through your Service, you're expecting it to have an effect. Write a Unit Test to test that effect. Depending on your particular needs, I'd say you might not need to have a test on the Repository Delete, particularly if that functionality is getting exercised as part of your Service Delete functionality, but it really all depends on what level of coverage you're trying for.
Also, if you had created this code with TDD, you would have had a test. It actually matters whether people can call Delete through your service, so you actually have to test it.
In my opinion you need to test both. Maybe you can do the creation EF context class in a seperate factory that can be tested more easy and mock the context class for the MyRepository tests. That will be more easy and using a factory for creating a context calls seems to be quiet useful for me.