TDD Function Tests - unit-testing

Should I write unit test for all nested methods or if writing one test for caller is enough?
For instance:
void Main()
{
var x = new A().AFoo();
}
public class A
{
public int AFoo()
{
// some logic
var x = new B().BFoo();
// might have some logic
return x;
}
}
public class B
{
public int BFoo()
{
// some logic
return ???;
}
}
Is that sufficient to write unit test for Main() method or I need to write tests for Main, A.AFoo(), B.BFoo() methods? How deep should I go?
Thanks in advance.

A testing purist would say that you need to create unit tests for classes A and B.
Each class should have all methods tested. If a method can do more than one thing (if you have an if statement, for example), then you should have a test for each path. If the tests are getting too complicated, it's probably a good idea to refactor the code to make the tests simpler.
Note as it stands right now, its hard to test A in isolation because it depends on B. If B is simple, as it is right now, it's probably ok. You might want to name your tests for A integration tests because technically they test both A and B together. Another option would be to have the method AFoo accept as a parameter the instance of B on which it operates. That way you could mock an instance of B and have a true unit test.

Unit tests are supposed to work on units, in the case of OOP the units are classes and the methods of the classes. That means that you should write a separate test class for each class under consideration, and at least one testing method for each method provided in the class. What is more, it is important to isolate the classes as much as possible so that a bug in class B does not cause a failure on class A. This is why Inversion of Control (Dependency Injection) is so useful, because if you can inject the instance of class B into the instance of class A, you can change B to be just a Mock object.
One of the reasons we write unit tests is to explain, in code, exactly how the methods of each class are expected to behave under all conditions, including and especially edge cases. It is hard to detail the expected behaviour of class B by writing tests on the main method.
I would recommend reading some material online explaining test driven development and how to mock objects, and perhaps use some of the excellent mocking libraries that exist such as JMock. See this question for more links.

Unit tests should help you to reduce your debugging effort. So when you just write unit tests for AFoo and none for BFoo, and one of your test fails, you probably won't know if the problem is part of class A or class B. Writing tests for BFoo too will help you to isolate the error in smaller amount of time.

Related

Unit testing: Required to mock methods of the class itself?

I've been doing some unit testing and just getting into the topic as a whole.
I stumbled upon the following scenario, suppose I have a class like this:
class A{
public B mehtod_1(B b){
b = method_2(b);
b = method_3(b);
b += 1;
return b;
}
public B method_2(B b){
// do something to B without external dependency
return B;
}
public B method_3(B b){
// do something else to B without external dependency
return B;
}
}
I can write tests for method_2 and method_3 without a problem, do different tests by configuring B in different ways and asserting the expected transformation on B after the call, those methods are atomic.
So my question is:
If I was to test method_1 in an atomic way I would have to mock the calls to method_2 and method_3 since if I would actually call these methods I would not test method_1 in an atomic manor.
In the latter case is method_2 was broken then the tests for method_1 and method_2 would break, and that would be misleading. If I'd mock the method_2 call inside the method_1 test, only the method_2 test would fail, giving a clearer indication of where the error is (namely somewhere in the business logic of method_1 given all other invoked methods worked as expected).
Did I understand the concept here correctly?
On the other hand it is correct, if both tests fail, since in the real world, method_1 cannot work without method_2 working.
My gut would say atomicity of tests is what is desired, meaning the first solution where there is one test for method_1, for every possible outcome of method_2 and method_3 (statically mocked).
Is there a "correct"/common/best practice way?
Immediate answer: in case we are talking Java here; and partial mocking is really of interest to you, you can look into using Mockito's spy concept.
But beyond that: you are getting unit testing wrong. What you call atomicity; I call worrying about implementation details. But it shouldn't matter "what exactly" that "method under test" actually does. You want to test the what, not the how.
Meaning: if that method has to call some other method(s) (that work fine in your unit test environment; without mocking); then there is no need thinking about mocking them!
You see: you care about the contract of each of your methods. That contract is what you want to test: given these input parameters, I expect that result/side effect/exception ...
Nonetheless, the fact that you have multiple public methods; and that they somehow depend on each other might be an indication of a design problem (as in: does it make sense that they are all public; is there some abstraction hiding in your interface that you should better express in other ways?). But that can only be decided given real code; real context.

If my unit test doesn't test logic, am I really accomplishing anything substantial?

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.

Is it bad practice to unit test a method that is calling another method I am already testing?

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.

Dependency Injection: Turtles all the way down?

So I'm wondering about how unit testing works in regards to dealing external dependencies. Here and elsewhere I've become familiar with dependency injection, and how that allows us to test a unit (A) of code. However, I'm confused about how to test other units (B and C) which are now possess the external dependency so they can inject it into the original unit (A).
For example, say some class Foo uses an external dependency...
class Foo
{
private ExternalDependency ed;
public int doSomethingWithExternalDependency() {...}
}
And class Bar makes use off Foo...
class Bar
{
public int doSomethingWithFoo
{
Foo f = new Foo();
int x = f.doSomethingWithExternalDependency();
// Do some more stuff ...
return result;
}
}
Now, I know that I can use dependency injection so that I can test Foo, but then how do I test Bar? I guess, I can, again, use dependency injection, but at some point some unit needs to actually create the external dependency; so how do I test that unit?
The examples you provide do not use Dependency Injection. Instead, Bar should use Constructor Injection to get a Foo instance, but there's no point in injecting a concrete class. Instead, you should extract an interface from Foo (let's call it IFoo) and inject that into Bar:
public class Bar
{
private IFoo f;
public Bar(IFoo f)
{
this.f = f;
}
public int doSomethingWithFoo
{
int x = this.f.doSomethingWithExternalDependency();
// Do some more stuff ...
return result;
}
}
This enables you to always decouple consumers and dependencies.
Yes, there will still be a place where you must compose the entire application's object graph. We call this place the Composition Root. It's a application infrastructure component, so you don't need to unit test it.
In most cases you should consider using a DI Container for that part, and then apply the Register Resolve Release pattern.
Keep in mind the difference between unit testing and integration testing. In the former, the dependency would be mocked whereby it provides expected behavior for the purpose of testing the class which consumes the dependency. In the latter, an actual instance of the dependency is initialized to see if the whole thing works end-to-end.
In order to use Dependency Injection, your classes would have their dependencies injected into them (several ways to do that - constructor injection, property injection) and would not instantiate them themselves, as you do in your examples.
Additionally, one would extract the interface of each dependency to help with testability and use the interface instead of an implementation type as the dependency.
class Foo
{
private IExternalDependency ed;
public int doSomethingWithExternalDependency() {...}
public Foo(IExternalDependency extdep)
{
ed = extdep;
}
}
What most people do is use a mocking framework to mock the dependencies when testing.
You can mock any object that the class under test depends on (including behavior and return values) - pass the mocks to the class as its dependencies.
This allows you to test the class without relying on the behavior of its (implemented) dependencies.
In some cases, you may want to use fakes or stubs instead of a mocking framework. See this article by Martin Fowler about the differences.
As for getting all the dependencies, all the way down - one uses an IoC container. This is a registry of all of the dependencies in your system and understands how to instantiate each and every class with its dependencies.
When you unit test a class, you should mock its dependencies, to test your class in isolation -- this is regardless of dependency injection.
The answer to your question about Bar is: yes, you should inject Foo. Once you go down the DI path, you will use it across your entire stack. If you really need a new Foo for every doSomethingWithFoo call, you might want to inject a FooFactory (which you can then mock for testing purposes), if you want a single Bar to use many Foos.
I'd like to stress out that in case of unit testing you should have two separate sets of tests: one for Foo.doSomethingWithExternalDependency and another one for Bar.doSomethingWithFoo. In the latter set create mock implementaion of Foo and you test just doSomethingWithFoo assuming that doSomethingWithExternalDependency works properly. You test doSomethingWithExternalDependency in a separate test set.

Writing maintainable unit tests with mock objects

This is a simplified version of a class I'm writing a unit test for
class SomeClass {
void methodA() {
methodB();
methodC();
methodD();
}
void methodB() {
//does something
}
void methodC() {
//does something
}
void methodD() {
//does something
}
}
While writing the unit tests for this class, I've mocked out objects using EasyMock used in each method. It was easy to set up the mock objects and their expectation
In method B,C,and D. But to test method A, I have to set up A LOT more mock objects and their expectations. Also, I’m testing method A in different conditions, meaning I have to setup the mock objects many times with different expectations.
In the end, my unit test becomes hard to maintain and pretty cluttered. I was wondering if anyone has or seen a good solution to this problem.
If I understand your question correctly, I think that this is a matter of design. The nice thing about unit testing is that writing tests often forces you to make your design better. If you need to mock too many things while testing a method it often means you should split your class into two smaller classes, which will be easier to test (and write, and maintain, and bugfix, and reuse, etc.).
In your case, the method A seems to be at a higher level than methods A, B, C. You can consider removing it to a higher level class, that would wrap SomeClass:
class HigherLevelClass {
ISomeClass someClass;
public HigherLevelClass(ISomeClass someClass)
{
this.someClass = someClass;
}
void methodA() {
someClass.methodB();
someClass.methodC();
someClass.methodD();
}
}
class SomeClass : ISomeClass {
void methodB() {
//does something
}
void methodC() {
//does something
}
void methodD() {
//does something
}
}
Now when you are testing methodA all you need to mock is the small ISomeClass interface and the three method calls.
You could extract common setup code into separate (possibly parametrized) methods, then call them whenever appropriate. If the tests for methodA have a very different fixture from the tests of the other methods, there may not be much to put into the #Before method itself, so you need to call the appropriate combination of setup helper methods from the test methods themselves. It is still a bit cumbersome, but better than duplicating code all over the place.
Depending on what unit test framework you use, there may be other options too, but the above should work with any framework.
This is an example of a Fragile test because the mock setups have too intimate knowledge of the SUT.
I don't know EasyMock, but with Moq you don't need to setup void methods. However, with Moq the methods would have to be public or protected and virtual.
For each test you're writing, consider the behaviour which is valuable for that test. You'll have some contexts you're setting up which the behaviour relies on, and some outcomes as a result of the behaviour that you want to verify.
Set up relevant contexts, verify the outcomes, and use NiceMocks for everything else.
I prefer Mockito (Java) or Moq (.NET) which work this way by default. Here's Mockito's page on Mockito vs. EasyMock so you can get the idea (EasyMock didn't have NiceMock before Mockito came along):
http://code.google.com/p/mockito/wiki/MockitoVSEasyMock
You can probably use EasyMock's NiceMock in a similar way. Hopefully this will help you detangle your tests. You can always import both frameworks and use them alongside each other / incrementally switch over if it helps.
Good luck!
I’m testing method A in different conditions, meaning I have to setup the mock objects many times with different expectations.
If you care of what methodA is doing and which collaborator function has to be called then you have to setup different expectations... I don't see how you can skip this step?!
If you testLogout you would expect a call to myCollaborator.logout() otherwise if you testLogin you would expect something like myCollaborator.login().
If you have many methods with lots/different expectations maybe is the case to split your class in collaborators