KevP
KevP

Reputation: 23

Using Pytest to test a Python Program

TI am quite new to Python Programming and have a question on testing using Pytest. In a high-level, I have a program that takes 3 pieces of user input and generates a text file in the end. For my tests, I want to basically compare the files my program outputted, with what it should be.

Now, I am not sure how to go about testing. The program itself takes no arguments, but just relies on 3 pieces of user input, which I'll use monkeypatch to simulate. Do I create a new python file called program_test.py and have methods in here that call the original program? I have tried this, but I'm having trouble actually calling the original program and sending in the simulated inputs. Or, do I have tests in the original program (which doesn't make much sense to me).

I want something like this:

import my_program

def test_1():
    inputs = iter(['input1', 'input2', 'input3'])
    monkeypatch.setattr('builtins.input', lambda x: next(inputs))
    my_program
    # now do some assertion with some file comparison
    # pseudocode
    assert filecompare.cmp(expectedfile, actualfile)

This just seems to be running the original program and I think its to do with the import statement i.e. it is never running test_1(), probably because I never call it? Any help would be appreciated!

Upvotes: 2

Views: 496

Answers (1)

vladsiv
vladsiv

Reputation: 2946

Without providing your my_program code it's hard to tell what's going on.

Since you are mentioning import problems, I guess your not defining main() and if __name__ == "__main__".

Here's a little example of how you can test that.

First, structure your my_program to have main function which contains the code and then add if __name__ == "__main__" which will allow you to run main function if the my_program is executed directly but also to import my_program as module to other files (without running it, for more information please see: What does if name == "main": do?).

my_program:

def main():
    x = input()
    y = input()
    z = input()
    with open("test", "w") as f_out:
        f_out.write(f"{x}-{y}-{z}")


if __name__ == "__main__":
    main()

Now you can create a test.py file and test the main function of my_program:

import os
import filecmp
import my_program


def test_success(monkeypatch):
    inputs = ["input1", "input2", "input3"]
    monkeypatch.setattr("builtins.input", lambda: next(iter(inputs)))
    my_program.main()
    with open("expected", "w") as f_out:
        f_out.write("-".join(inputs))
    assert filecmp.cmp("expected", "test")
    os.remove("test")
    os.remove("expected")


def test_fail(monkeypatch):
    inputs = ["input1", "input2", "input3"]
    monkeypatch.setattr("builtins.input", lambda: next(iter(inputs)))
    my_program.main()
    with open("expected", "w") as f_out:
        f_out.write("something-else-test")
    assert not filecmp.cmp("expected", "test")
    os.remove("test")
    os.remove("expected")

This is an example so I used os.remove to delete the files. Ideally you would define fixtures in your tests to use tempfile and generate random temporary files which will be automatically deleted after your tests.

Upvotes: 2

Related Questions