0

Earlier I haven't cared much about writing tests, but now I want to have a look at it. But I directly run into problems. There are many tutorials about how to writes tests, but I haven't found anything about how to when a package requires another (not built-in) package to work.

I have two packages; let's call them foo and bar. The package bar requires foo to work. Now I want to write a test for bar.

What is the best/recommended solution to make sure that foo is installed somewhere so that bar can find foo when the tests are run? Is it to just manually install foo before testing bar?

Note: Neither of the packages is published to PyPI.

md2perpe
  • 3,372
  • 2
  • 18
  • 22
  • Please give an example of what you tried out. The question is very general. – MUNGAI NJOROGE Jun 22 '19 at 15:29
  • @MUNGAINJOROGE. I haven't tried anything out because I wanted to learn the recommended way to do it. And my question is general because it is a generic problem. Showing the code of my packages would make the question clearer. – md2perpe Jun 22 '19 at 20:03
  • Then, whether the packages are in PyPi or Not, give ``bar`` the responsibility of finding ``foo``. Which means that when writing tests you are actually testing bar and you don't have to care about its dependencies. You might want to have a look at python packages/modules https://realpython.com/python-application-layouts/ – MUNGAI NJOROGE Jun 24 '19 at 06:40
  • @MUNGAINJOROGE. How would you solve it so that `bar` finds `foo`? – md2perpe Jun 24 '19 at 07:48
  • Assuming you are on Linux, create a directory in $HOME/python_private_modules, then append this to $PYTHONPATH in .bashrc as ``export PYTHONPATH=$PYTHONPATH:$HOME/python_private_modules``. Add ``foo`` into this directory and now in any python project you will be able to do ``import foo``. – MUNGAI NJOROGE Jun 24 '19 at 09:19

1 Answers1

0

Without more information, my guess is that your problem is that foo cannot be found when you're running your tests for bar (e.g. a ValueError: Attempted relative import in non-package). If that's the case, then your problem is likely due to your project's file/dir organization (see this SO post for a solution).

Alternatively, perhaps your problem is that you don't have the foo package located within bar as a submodule. Or maybe you don't have foo pip installed globally. If this is the case, then you need to set up a virtual environment (the built-in venv library is one way) where foo is pip installed. You mentioned that foo isn't on PyPi, but if you've got it on GitHub you can easily add it to a requirements.txt to have it pulled and installed within your virtual environment.

If those solutions don't answer your question, then maybe you're in fact asking about how you can control the behavior of foo when bar is under test? If so, then you should look into mocking and/or patching, which are ways you can create an 'fake' object within your test suite to imitate and substitute for another object within your program. In your case, you want to patch foo so that your test(s) for bar don't depend on how foo behaves. Isolating bar like this is integral to the concept of unit testing.

Assuming you're using unittest, there's the excellent unittest.mock module. unittest.mock provides a class called Mock that you can use to imitate real objects in your codebase. The library also provides a function called patch() that replaces the real objects in your code with Mock instances. You can use patch() as either a decorator or a context manager, giving you control over the scope in which the object will be mocked. Once the designated scope exits, patch() will clean up your code by replacing the mocked objects with their original counterparts. I've found this article to be handy when getting started with Mock and patch().

Hopefully I somehow answered your question. If not, let me know and I can update!

Scott McAllister
  • 468
  • 7
  • 12
  • Making `foo` a submodule of `bar` doesn't sound like a good solution. What if I would have several unrelated packages, all depending on `foo`? I cannot make `foo` a submodule of all of the. That would also make it a bit difficult to install `foo` without having to also install `bar`. – md2perpe Jun 22 '19 at 20:11
  • Mocking also doesn't sound correct in this case. The library `foo` implements points and vectors, among other geometric things. The library `bar` uses points and vectors. Had `foo` implemented some kind of service then dependency injection and mocking could have been a proper solution, but I don't think that it is in this case. – md2perpe Jun 22 '19 at 20:21
  • Anyway, thanks for your answer. It is correct that my problem is that `foo` cannot be found when I'm running my tests for `bar`. The question is what is the best way to make sure it is. – md2perpe Jun 22 '19 at 20:23