2

I'm trying to unit test a small program I wrote.
My problem is that I can't see an easy way to unit test my top level class (Matcher) that exposes a single public method (MatchAll).
I do have tests for my inner classes, but they are largely trivial.

Let me present a problem and a sketch of my solution:

Problem: Given list of people, list of their preferred teams and rankings for each team, find a match that both maximizes team rank and takes candidate preferences into consideration.

My solution:

  • Candidate - Holds a list of preferred teams and a rank score for each respective team
  • Team - Holds list of accepted candidates. As long as the team has room, it accepts any candidate. Once it fills up, it only accepts candidates that improve its score. It also purges the candidate with lowest score.

Team exposes the following methods:

  1. IsBetterMatch
  2. Add
  3. PurgeWeakest

Matcher - Contains the list of candidates and list of teams and implements the core logic of assigning candidates to a team.

My matching logic is as follows (Pseudocode):

function Matchall()
    while candidates != empty
        c <- candidates.getFirst()      
        for each t in c.teams
            betterMatch = t.IsBetterMatch(c)
            if betterMatch
                weakest = t.purgeWeakest()
                t.Add(c)
                candidates.add(weakest)

Assuming team methods are thoroughly tested, how would you suggest to test this function?

The tests that I can think of for this function are very complex both to formulate and to setup.

For example:

When two candidates have same rank and want the same team and the team has room for only one, the first one should be assigned to the team. Second one should be assigned to another team down his preference list.

It seems to me that they fall more under the integration tests category, which is why I'm confused. It's my understanding that the unit tests should be short and simple to write

  • 2
    Delete the function, write a failing test, then write the function again following strict TDD. Even if it's just an exercise, it will force you to write testable code. – Tim Apr 16 '15 at 13:10
  • Although Tim's answer probably isn't sufficient, it is a nice exercise suggestion. – MetaFight Apr 16 '15 at 13:19
  • 5
    It's unclear to me what's unclear to you. You inject a couple of teams and rankings, determine beforehand what result should be returned and verify that it is in fact returned. Then you write another test for two teams that result in an equal match and verify equality returns the correct result. Do this for each distinct scenario. Can you specify what you're having trouble with? – Jeroen Vannevel Apr 16 '15 at 13:26
  • Jeroen's comment is what I would say, with this addition. It seems like an integration test because you are doing an integration test by the strictest definition. You are integrating with the Team and Candidate classes. However, that's the route most people would probably take. The other route would be to mock your Team and Candidate classes in order to give yourself very explicit control of the results, but I don't know how that might help you because Team and Candidate seem so trivial. – Dunk Apr 17 '15 at 16:41
  • To add to Jeroen's good point: You could create some helper functions for your test to simplify creation of teams and rankings for your tests. Then the seemingly huge effort for setting up the fixture of each test may turn out quite manageable. – Dirk Herrmann Feb 5 '18 at 22:38
2

In order to test a method which accepts no arguments and returns no results you have to fiddle with the state that it works on, invoke it, and then examine the state that it modified by side-effect. I would strongly advice against doing that, and if that's how your top-level method has to be, then it is untestable as far as I am concerned. (Not objectively untestable, but not worth the effort in my opinion.)

What you can do, however, is to turn your top-level method into nothing but a wrapper which simply invokes a mid-level method that accepts arguments, works on nothing but the arguments that it accepts, and returns a result.

Then, you can test the mid-level method by passing it sample arguments and checking to make sure that it returns expected results.

  • 1
    I disagree with: You cannot test a method which accepts no arguments and returns no results. If function void foo() changes the state of the object/program, and you can measure that change, then you can check for an expected state after running foo. – Shaz Apr 16 '15 at 14:41
  • @Ryan you are right, I reworded. – Mike Nakis Apr 16 '15 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.