Who tests the unit tests? – Anon

Ever since I was introduced to the concept of Test Driven Development (TDD) and Unit Testing back in 2006, I fell in love with it. So much that it got me fired from my first project and later on to get an outstanding employee award in the second project.

Most of that testing was done in Microsoft .Net (nUnit) and C++ (using custom build framework at the time) and more recently with jUnit and it’s relatives in Java during my short tryst with Android development. But those were real easy compared to how one tests with ATF.

One of the reasons I probably found this a bit overwhelming is because of my lack of exposure to a large system with collections of multiple interdependent and interconnecting components which deals with the most basic fundamentals of running an operating system. Application level testing like an Android Application or .Net one for that matter assumes you have a base operating system up and running be it Windows / Linux / BSD or some variant and your tests generally fall within the limits of the application which you are testing which are pretty much well defined business logic from a design specification of the application.

Unit testing / Functional testing for an operating system and it’s most fundamental components like uvm (the virtual memory manager) was clearly out of scope to me when I was first given the task of this project. Cherry (cherry@) approach of exposing the uvm_physseg.c to the userland was definitely one step towards doing unit / functional testing, but this was not enough. What else is needed to make the circle of testing complete?

After reading through the code in uvm_physseg.c I came across the following facts to differentiate between unit testing and functional testing in the ATF environment.

  • Functions exposed directly were subjected to testing.
  • Static functions were not tested.
  • Test nomenclature was simple, you give the name of the function as the name of your test. For example if you were testing the function uvm_physseg_delete() then the test name would be uvm_physseg_delete.
  • Unit Test nomenclature had the word unit prepended to the function name. In the above example if you were writing the tests for uvm_phsseg_delete() then the test name would be unit_uvm_physseg_delete.

The differentiation between a unit and functional test was simple, in a Unit test you setup the variables / parameters you need to pass into the function (if any) or the function uses / requires ahead of the function call and then invoke the function and test for conditions. In a functional test you call the function to be tested in the natural way it is supposed to be invoked, meaning you setup all the preconditions upto the funtion call like you would expect to happen if the system were running in actual production. This means functional test cases are allowed to have multiple calls to other dependent function calls before the invocation of the function which is being tested.

An example showing the unit test variant vs the functional test variant of the same function witin uvm_physseg.c

Unit Test case for uvm_physseg_start()
ATF_TC(unit_uvm_physseg_start);
ATF_TC_HEAD(unit_uvm_physseg_start, tc)
{
	atf_tc_set_md_var(tc, "descr", "unit test for working of uvm_physseg_start()");
}
ATF_TC_BODY(unit_uvm_physseg_start, tc)
{
	struct uvm_physseg *seg; /* A test segment */

	/* Allocate valid memory for each of the segments */
	seg = malloc(sizeof(struct uvm_physseg));

	ATF_REQUIRE(seg != NULL);

	seg->start = START_TESTS_START;

	ATF_CHECK_EQ(seg->start, uvm_physseg_start(seg));
}
Functional Test case for uvm_physseg_start()
ATF_TC(uvm_physseg_start);
ATF_TC_HEAD(uvm_physseg_start, tc)
{
	atf_tc_set_md_var(tc, "descr", "test for checking the start address of a valid segment");
}
ATF_TC_BODY(uvm_physseg_start, tc)
{
	/* A test Segment */
	struct uvm_physseg *seg;

	sfn_t start, end, avail_start, avail_end;

	/* props[] check - single item */
	struct uvm_physseg_prop props[UVM_PHYSSEG_TYPE_COUNT] = {
		{
			UVM_PHYSSEG_DMA,
			{
				UVM_PHYSSEG_DMA_CAT1
			}
		}
	};

	start = avail_start = VALID_START_1;
	end = avail_end = VALID_END_1;

	seg = uvm_physseg_plug(start, end,
	    avail_start, avail_end, props);

	ATF_REQUIRE(seg != NULL);

	ATF_REQUIRE(seg->pgs != NULL);

	ATF_CHECK_EQ(VALID_START_1, uvm_physseg_start(seg));
}