Question

I have been reading about unit tests and functional tests for a while now.

If I write exhaustive functional tests, won't they in-turn cover the units underneath as well, which in-turn make the unit tests redundant?

We follow agile and we write the functional tests using WebDriver as soon as we are done with the 'slice' of the functionality, which is typically 2-4 weeks of sprint time.

Was it helpful?

Solution

Perhaps, but not necessarily.

Functional tests can be thought of as "Black Box" tests whereby you are looking at a specific function (regardless if that's a single method, module, system, etc) and checking that for a given input, you get a given output.

However, if the functional test fails all you can say is that the system is faulty; it doesn't necessarily give you any indication of what part of the system is to blame. Of course you will go off and diagnose the problem but you don't know up front what the problem is.

e.g

//assuming you have a UserService that amongst other things passes through to a UserRepository
    var repo = new UserRepository();
    var sut = new UserService(repo);
    var user = sut.GetUserByID(1);
    Assert.IsNotNull(user); //Suppose this fails.

In the above case, you don't know if it's because the UserService's GetUserByID() function is faulty - perhaps it did not call repo.GetUserByID and just returned null, perhaps it did get a User from repo but accidentally then returned an uninitialized temp variable, etc - or perhaps it's because the dependency (repo) itself is faulty. In any case, you'll have to debug into the issue.

Unit tests, on the other hand, are more like "White Box" tests whereby you have effectively taken the cover off the system and are testing how the system behaves in order to do what you want it to do.

e.g. (code below may not compile and is just for demo purposes)

//setup a fake repo and fake the GetUserByID method to return a known instance:
    var repo = new Mock<UserRepository>();
    var user = new User{ID=1;}
    repo.Setup(r=>r.GetUserByID(1).Returns(user);
    var sut = new UserService(repo.Object);
    var actual= sut.GetUserByID(1);
    //now make sure we got back what we expected. If we didn't then UserService has a problem.
    Assert.IsNotNull(user);
    Assert.AreEqual(user,actual);

In this case you are explicitly verifying that sut.GetUserByID() behaves in the expected way - that it invokes the repo.GetUserByID() and returns resultant object, without mangling it or changing it.

If this unit test passes, but the functional test fails, you can say with confidence that the problem does not lie with the UserService, but with the UserRepository class, without even looking at the code. That may or may not save you time, it really depends on how complex your functional units are.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top