1

Imagine there is a number of filter functions that all perform filtering of items in a list based on different criteria. Say there are 5 such filter functions. All unit tested

Now imagine there is another function that takes a list of items, 5 arguments (not necessarily homogeneous), based on these arguments it decides which filters to "activate" and at the end uses "activated" filters

Example pseudocode:

def filter_list(list, arg1, arg2, arg3, arg4, arg5)
    activated_filters = []
    if (some condition for arg1)
        activated_filters.append(filter1)
    if (some condition for arg2)
        activated_filters.append(filter2)
    ...

    filtered_list = filter(activated_filters, list)
    return filtered_list

How would one go about unit testing this function? Even though each filter has been unit tested separately and is verified to work, the function based on some simple and some not so simple conditions is activating each filter accordingly.

Given the number of arguments and large number of possible combinations, having large test coverage seems to be difficult.

The actual logic inside the function is fairly simple, based on some conditions filters are either applied or not.

I am looking to either come up with a good test strategy or a suggestion to refactor function in question. If any help, language is Python

1
  • The normal considerations and metrics for tests (branch/path/case coverage, edge case testing, etc. etc.) apply. There is no reason to do anything notably different just because you're testing a higher-order function. Oct 1, 2020 at 6:11

2 Answers 2

3

Let me assume by providing the right values to list, it should be simple to deduce from the returned value of the function whether a certain filter was applied, or not. If the filters are very complex functions, you may need to replace them by injecting some mock filters during the test to reach that goal, but that should be pretty straightforward.

From this starting point, it is not that difficult to get a satisfying "test coverage". I would recommend to start with some classic test case design techniques:

  1. One should provde a test case to get full code coverage (which is easy: provide one test case for arguments fullfilling all the conditions)

  2. One should provide test cases to get full branch coverage, so a set of cases where each condition is fulfilled one time, and not fullfilled another time. So a pair of two tests which are complementary will be fine

  3. Edge and boundary cases: provide test cases where 0 conditions are fulfilled, all five conditions are fullfilled, just one condition is fullfilled, all but one conditions are fullfilled. Also cases where the provided list is empty, has just one element, has enough elements to validate if the conditions were correctly evaluated.

These ideas may be extended by some randomly picked combinations, some "real world" combinations, and (in the future, when the function was used in production) cases where bugs showed up, to prevent regressions.

Of course, this may still lead to a certain number of test cases which you may consider as a huge number, but not to the combinatorial explosion of all possible input combinations.

3

There are two things going on in your function: composing the filters, and filtering the list. These are two distinct phases, and thus can easily be refactored into two methods: compose_filters which takes the five args, and filter_list which takes the aggregated filter and applies it.

Separating compose_filters means you have a clear path to testing: pass in all (meaningful) combinations of arg1..arg5, and see if the output contains the expected filters.

Separating filter_list means you have a clear path to testing too: pass in meaningful values of filters (empty, one filter, all filters, same filters in different order, etc) with a known base list, and check the output.

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.