I am working on unit testing and I am trying to increase the line coverage to 90% of a class. The class contains lot of predicate methods which only compare some of its fields and based on that it returns true or false.
My question is, should I write unit tests for those predicate methods or not.
Currently, I have written unit tests which just initialize the object and set its fields and then assert if return value of predicate is correct.
For example:
public boolean isScheduled() {
return getShippingDate() != null;
}
How should I unit test it and what should be the unit test method name?
Thanks.
I would suggest you, add a test for the code even if there is a small piece of logic involved in there.
My preference for naming would be like:
methodName+ExpectedReturnValue+Behaviour
For example, in your case, I would name it as
isScheduledShouldReturnTrueWhenShippingDateIsNotNull - positive case
isScheduledShouldReturnTrueWhenShippingDateIsNotNull - negative case
Follow the same naming convention across the repository (not necessarily the one that I suggested). You can also merge both cases in one test.
Remember that tests are the documents, so it is okay to have the method name verbose.
Code:
#Test
public void isScheduledShouldReturnTrueWhenGetShippingDateIsNotNull() {
ClassA classA = new ClassA();
classA.setShippingDate("date");
boolean isScheduled = classA.isScheduled();
assertTrue(isScheduled);
}
PS: Ideally, the motive should never be like increasing the coverage to get some good reports. What matters is the quality of the tests.
Related
I'm new to unit testing, and I'm using NSubstitute for mocking. I have read a few articles on the high level purpose of unit testing, and a lot of the rationales are pretty agreeable. However, I can't seem to understand how my test is worthwhile if it isn't testing any logic in a concrete class.
Using the example from NSubstitute's documentation (http://nsubstitute.github.io/help/getting-started/), let's assume a basic calculator interface:
public interface ICalculator
{
int Add(int a, int b);
string Mode { get; set; }
event EventHandler PoweringUp;
}
We'll use NSubstitute to substitute an instance, specify a return, and use an Assert for testing:
calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2).Returns(3);
Assert.That(calculator.Add(1, 2), Is.EqualTo(3));
Because we've specified that 3 will always be returned when 1 and 2 are passed to the Add method, how does this help us test potentially faulty logic that exists inside a concrete class that implements the ICalculator interface? And if it doesn't, why is this test worthwhile at all?
Thanks!
Unit tests, as you noted, are (mainly) meant to test logic. In the example you've given, you're testing that a mocked object returns the expected mocked result - so unless you're developing nsubstitute itself and want to test that it successfully substitutes an object, you're right, this is pretty meaningless.
Mocking is usually used to check the logic of a collaborator class. For example, consider this (stupid) method that takes some action if two numbers add up to three:
public boolean AreTheyThree(int a, int b, ICalculator calc)
{
return calc.Add(a, b) == 3;
}
Now, if you'd like to test a method like this, it makes sense to mock (substitute) the ICalculator you're using, since you don't want to rely on specific implementation details, or have the test for your logic fail if a regression is introduced to a specific ICalculator implementation:
calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2).Returns(3);
Assert.That(myObject.AryTheyThree(1, 2, calculator), Is.EqualTo(true));
Your test is not worthwhile because you are not testing logic. At this point you are only testing if your testing framework is correct. To make your test worthwhile you should test the logic depending on calculator.Add and let the add return 3. Make a separate test for you add function. By isolating your code into units which can be validated separately. If you are testing the code depending on the Add function you do not want that code to fail because your Add implementation is not correct. It should assume your Add function is correct because it is tested separately.
Using this article I now want to test some repositories.
I use Moq to make a mock of the repository, and setup the GetAll, and GetByID methods.
The unit test passes, and everything is good.
But when I comment out the code in GetAll() in the repository class and put in a NotImplementedException() the unit test still passes.
Would that mean that if I make some changes to the code, the new implementation of GetAll() could break my code while still letting my tests pass?
It means your unit tests are incomplete: you have to test both valid and invalid situations. As you indicate yourself: you want to know when something works but you also want to know when it fails.
Consider the following two examples:
#Test(expected = PersonNotFoundException.class)
public void GetPerson_WithNonExistingId_ShouldThrowPersonNotFoundException(){
Person person = new PersonRepository().getPersonById(-1);
}
#Test
public void GetPerson_WithExistingId_ShouldReturnPerson(){
Person person = new PersonRepository().getPersonById(5);
Assert.AssertNotNull(person);
}
Now you have two tests that will verify the method's behaviour both when it is supposed to work and when it shouldn't. If you now suddenly change the implementation of PersonRepository.getPersonById(int) to always throw PersonNotFoundException, your first test will still succeed but the other one won't.
It is advised to validate the spectrum of distinct input paths. This often includes
Passing null values
Passing out-of-bound values
Passing negative values
Passing non-existing values
etc
I realized too late that Moq is C#, not Java. This idea is language-agnostic though and the code speaks for itself.
Consider the following class:
public class MyIntSet
{
private List<int> _list = new List<int>();
public void Add(int num)
{
if (!_list.Contains(num))
_list.Add(num);
}
public bool Contains(int num)
{
return _list.Contains(num);
}
}
Following the "only test one thing" principle, suppose I want to test the "Add" function.
Consider the following possibility for such a test:
[TestClass]
public class MyIntSetTests
{
[TestMethod]
public void Add_AddOneNumber_SetContainsAddedNumber()
{
MyIntSet set = new MyIntSet();
int num = 0;
set.Add(num);
Assert.IsTrue(set.Contains(num));
}
}
My problem with this solution is that it actually tests 2 methods: Add() and Contains().
Theoretically, there could be a bug in both, that only manifests in scenarios where they are not called one after the other. Of course, Contains() now servers as a thin wrapper for List's Contains() which shouldn't be tested in itself, but what if it changes to something more complex in the future? Perhaps a simple "thin wrap" method should always be kept for testing purposes ?
An alternative approach might suggest mocking out or exposing (possibly using InternalsVisibleTo or PrivateObject) the private _list member and have the test inspect it directly, but that could potentially create test maintainability problems if someday the internal list is replaced by some other collection (maybe C5).
Is there a better way to do this?
Are any of my arguments against the above implementations flawed?
Thanks in advance,
JC
Your test seems perfectly OK to me. You may have misunderstood a principle of unit testing.
A single test should (ideally) only test one thing, that is true, but that does not mean that it should test only one method; rather it should only test one behaviour (an invariant, adherence to a certain business rule, etc.) .
Your test tests the behaviour "if you add to a new set, it is no longer empty", which is a single behaviour :-).
To address your other points:
Theoretically, there could be a bug in both, that only manifests in scenarios where they are not called one after the other.
True, but that just means you need more tests :-). For example, add two numbers, then call Contains, or call Contains without Add.
An alternative approach might suggest mocking out or exposing (possibly using InternalsVisibleTo) the private _list member and have the test inspect it directly, but that could potentially create test maintainability problems[...]
Very true, so don't do this. A unit test should always be against the public interface of the unit under test. That's why it's called a unit test, and not a "messing around inside a unit"-test ;-).
There are two possibilities.
You've exposed a flaw in your design. You should carefully consider if the actions that your Add method is executing is clear to the consumer. If you don't want people adding duplicates to the list, why even have a Contains() method? The user is going to be confused when it's not added to the list and no error is thrown. Even worse, they might duplicate the functionality by writing the exact same code before they call .Add() on their list collection. Perhaps it should be removed, and replaced with an indexer? It's not clear from your list class that it's not meant to hold duplicates.
The design is fine, and your public methods should rely on each other. This is normal, and there is no reason you can't test both methods. The more test cases you have, theoretically the better.
As an example, say you have a functions that just calls down into other layers, which may already be unit tested. That doesn't mean you don't write unit tests for the function even if it's simply a wrapper.
In practice, your current test is fine. For something this simple it's very unlikely that bugs in add() and contains() would mutually conspire to hide each other. In cases where you are really concerned about testing add() and add() alone, one solution is to make your _list variable available to your unit test code.
[TestClass]
public void Add_AddOneNumber_SetContainsAddedNumber() {
MyIntSet set = new MyIntSet();
set.add(0);
Assert.IsTrue(set._list.Contains(0));
}
Doing this has two drawbacks. One: it requires access to the private _list variable, which is a little complex in C# (I recommend the reflection technique). Two: it makes your test code dependent on the actual implementation of your Set implementation, which means you'll have to modify the test if you ever change the implementation. I'd never do this for something as simple as a collections class, but in some cases it may be useful.
Given the following SUT, would you consider this unit test to be unnecessary?
**edit : we cannot assume the names will match, so reflection wouldn't work.
**edit 2 : in actuality, this class would implement an IMapper interface and there would be full blown behavioral (mock) testing at the business logic layer of the application. this test just happens to be the lowest level of testing that must be state based. I question whether this test is truly necessary because the test code is almost identical to the source code itself, and based off of actual experience I don't see how this unit test makes maintenance of the application any easier.
//SUT
public class Mapper
{
public void Map(DataContract from, DataObject to)
{
to.Value1 = from.Value1;
to.Value2 = from.Value2;
....
to.Value100 = from.Value100;
}
}
//Unit Test
public class MapperTest()
{
DataContract contract = new DataContract(){... } ;
DataObject do = new DataObject(){...};
Mapper mapper = new Mapper();
mapper.Map(contract, do);
Assert.AreEqual(do.Value1, contract.Value1);
...
Assert.AreEqual(do.Value100, contract.Value100);
}
i would question the construct itself, not the need to test it
[reflection would be far less code]
I'd argue that it is necessary.
However, it would be better as 100 separate unit tests, each that check one value.
That way, when you something go wrong with value65, you can run the tests, and immediately find that value65 and value66 are being transposed.
Really, it's this kind of simple code where you switch your brain off and forget about that errors happen. Having tests in place means you pick them up and not your customers.
However, if you have a class with 100 properties all named ValueXXX, then you might be better using an Array or a List.
It is not excessive. I'm sure not sure it fully focuses on what you want to test.
"Under the strict definition, for QA purposes, the failure of a UnitTest implicates only one unit. You know exactly where to search to find the bug."
The power of a unit test is in having a known correct resultant state, the focus should be the values assigned to DataContract. Those are the bounds we want to push. To ensure that all possible values for DataContract can be successfully copied into DataObject. DataContract must be populated with edge case values.
PS. David Kemp is right 100 well designed tests would be the most true to the concept of unit testing.
Note : For this test we must assume that DataContract populates perfectly when built (that requires separate tests).
It would be better if you could test at a higher level, i.e. the business logic that requires you to create the Mapper.Map() function.
Not if this was the only unit test of this kind in the entire app. However, the second another like it showed up, you'd see me scrunch my eyebrows and start thinking about reflection.
Not Excesive.
I agree the code looks strange but that said:
The beauty of unit test is that once is done is there forever, so if anyone for any reason decides to change that implementation for something more "clever" still the test should pass, so not a big deal.
I personally would probably have a perl script to generate the code as I would get bored of replacing the numbers for each assert, and I would probably make some mistakes on the way, and the perl script (or what ever script) would be faster for me.
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.