Asymptotic complexity of multiple binary search Since binary search is \$O(log(n))\$.  Consider this example where I am searching for the existence of e and l and f in the word.

Is this \$O(n log(n))\$ or \$O(3 log(n))\$ and thereby still \$O(log(n))\$?

def search(array, item):

    if not array:
        return False

    if len(array) == 1:
        return array[0] == item

    mid = len(array) // 2
    left = array[:mid]
    right = array[mid:]

    return search(left, item) or search(right, item)


def elfish(word, letters):
    """
    &gt;&gt;&gt; elfish('', 'efl')
    False

    &gt;&gt;&gt; elfish('whiteleaf', 'elf')
    True

    &gt;&gt;&gt; elfish('whiteleaf', 'elf')
    True

    &gt;&gt;&gt; elfish('unfriendly', 'elf')
    True

    &gt;&gt;&gt; elfish('waffles', 'elf')
    True

    &gt;&gt;&gt; elfish('waffles', 'elf')
    True

    &gt;&gt;&gt; elfish('sameh', 'elf')
    False

    &gt;&gt;&gt; elfish('wolf', 'elf')
    False

    """
    result = True
    for letter in letters:
        result = result and search(word, letter)
    return result


elfish('waffles', 'elf')


The pure Python way of doing this is:

if 'e' in word and 'l' in word and 'f' in word:
    return True


Is Python doing a binary search in the background?
There are multiple problems in your approach - but they are more at the conceptual level, not in the style of the code, which is just fine. The unit tests are also commendable. But:


The algorithm you have coded is not the binary search algorithm.
The code implements a recursive search algorithm in an unsorted array. It has \$O(n)\$ time complexity and \$O(log(n))\$ space complexity - a clearly suboptimal for this task. The space complexity comes from the recursive function calls and the fact that Python does not optimize tail recursion. While you do demonstrate that solving the problem with recursion is possible, it is not the best option in terms of efficiency.
If you do implement binary search, sort the array first. To find the value I suggest using the functions from bisect module rather than reinventing the wheel, if this is a production code.
The Python in operator does not use binary search, as it has to avoid sorting the string, so binary search would not work; however, it does use some advanced string search algorithms, so is better than a naive version.


In this loop:


    for letter in letters:
        result = result and search(word, letter) 


it is clear that the answer will be False as soon as the first search() call fails. Therefore you can if not search(word, letter): return False for better efficiency, and don't need the result variable.

This is an alternative version that:


Has \$O(max(||letters||, ||word||))\$ effective complexity (assuming
\$O(1)\$ for set insertion and lookup) due to the use of counting sort.
Increases the average efficiency by returning False immediately after the first missing character is encountered



def elfish(word, letters):
    present_characters = set()
    for c in word:
        present_characters.add(c)
    for letter in letters:
        if letter not in present_characters:
            return False
    return True