Quick Index
Overview


Unit tests are simply program code (dtest) that tests (domain) program code.

We call them "unit tests" because we are testing units (objects/models).

Generally we tests something like:


The unit test name is not an exact science -- these are only suggested names.

General Unit Test Pattern 💡


Tests basically follow this "1-2-3" pattern:


Note: the "comparison" can be done by printing and checking visually. Later you can add more sophistication to your test (i.e. let the computer do comparisons for you).

Smoke Test


The "smoke test" is a great initial test. It answers this question -- do we have a forest fire? In coding terms -- does our software "blow up" while doing essential (core) operations? Or, does our software "not even start up"?

It's an important test because the worst thing is to deliver to another team (or grader) software that is on fire (doesn't work at all). The other team will not be able to use it -- and their work will likely be "blocked" if they depend on it. And, the grader, if they can't even start the software, will not be able to give us many points, if even any at all.

Basically smoke tests exercise essential/core parts of the software code.

Smoke Test Purpose
The purpose is to test the essentials
Example 1
Believe it or not, this little smoke test can find a number of blocker bugs: run problems, construction problems, message problems.
let array = new DynamicArray();
println(array.size());
Example 2
Recognizing that "add" is a essential core method, we run a smoke test that sends "add".
let array = new DynamicArray();
array.add('asha@hello.com');
println(array.size());

Functional Test


After smoke testing, we have "functional testing" -- e.g., "Is our software giving the correct answers?"

Functional tests compare actual results vs expected results.

Functional tests "cover" as many public methods as possible. Ideally, there is one or more functional tests for each public method.

Testing Lessons Learned


Start with 'Smoke Tests' to Find 'Blocker Bugs'


First make sure that simple "smoke tests" pass.

Continue with Functional Testing


After smoke tests are passing, then add functional tests (which compare "actual" vs "expected" results).

Do Not Put Test Code in Same Directory as Domain/Model Code


Graders and object will be using/testing our objects from "other" directories (and importing our files as needed) so we want to do similar. Otherwise, there is a good chance we'll miss bugs that they will hit (and these could be "blocker bugs").

If we put our test code in another directory (apart from our model/domain) then we will exercise/test required "imports" etc of our code.

By domain/model we mean our data structures (e.g. dynamic arrays, linked lists, trees, etc).

Test Objects (Not Just Primitives)


When testing a data structure we do not want to just test primitive element types like integers, strings, etc.

We also want to make sure our data structures work with "proper objects". These can be anything (e.g. customers, employees, stars, books, etc.).

We generally want to design the object types (classes) to have a unique key (e.g. customer number, employee number, star id, book ISBN, etc).

Equals Over '=='


Generally in object languages the operator "==" works for primitive values only (not proper objects).

So in your test code (and domain code) you should try to use the flavor an available version of "equals".

To support object equality, you will also likely need to implement "equals" in any object types (classes) you are using for tests.

Collections Take Special Care


We need to take special care when comparing collections.

We will need to verify that our equality checks are working for something like "collection1.equals(collection2)".

We may need to add helper/support methods to get these checks to work properly.

Test Code Styles


Overview


Test code can be simple to sophisticated.

It does not need to be sophisticated to be useful, especially for small projects.

Example Tests (Different Test Strategies)


These examples are in Java syntax but the ideas apply to other objects languages like JavaScript, etc.

Examples are here...

Simple Unit Test Examples


Overview


This page contains a couple simple unit test examples.

Examples


The examples are in pseudocode.

Convert them to your specific language (Js, Java, etc) to meet the syntax of your language. Especially note:


Example 1 -- Testing with Primitives


Example Pseudocode
Testing with primitives (e.g. integers, strings, doubles) is an okay way to get started testing. But see "lessons learned" on testing with "proper objects".
class DynamicArrayTest  {

	test_get_usingStrings() {

		let nm1 = 'Asha';
		let nm2 = 'Kofi';
		let dynamic = DynamicArray.newEmpty();
		dynamic.add(nm1);
		dynamic.add(nm2);
	
		var result, expected;
	
		result = dynamic.get(0);
		expected = nm1;
		this.show(result.toString());
		this.show(expected.toString());
	
		result = dynamic.get(1);
		expected = nm2;
		this.show(result.toString());
		this.show(expected.toString());
	
		//we could also test "first" and "last" the same way
	}
	
	//...
}



Example 2 -- Testing with Proper Objects


Example Pseudocode
You'll need to also code a testee object (to test with) -- in this example we use "Customer" -- download here for an example....
class DynamicArrayTest  {

	test_get_usingProperObjects() {

		let customer1 = Customer.fromFnameLnamePhoneZip('Kofi', 'Lee', '1112223333', 55100);
		let customer2 = Customer.fromFnameLnamePhoneZip('Asha', 'Woods', '9991231234', 55300);
		let dynamic = DynamicArray.newEmpty();
		dynamic.add(customer1);
		dynamic.add(customer2);

		var result, expected;

		result = dynamic.get(0);
		expected = customer1;
		this.show(result.toString());
		this.show(expected.toString());

		result = dynamic.get(1);
		expected = customer2;
		this.show(result.toString());
		this.show(expected.toString());
	}
	
	//...
}



Navigation