Issue
I'm testing a function which its main purpose is to allocate a file to a folder received in the parameters of this function. To do this, I create a empty file in my root folder and test for some different parameters for path. To be more explicit, here's a example:
alocate_file('folder1','folder2','folder3', 'file.txt')
This line will result in this allocation:
root/Downloads/folder1/folder2/folder3/file.txt
Some extra characteristics of my function: The Downloads folder is implicit, it receive a list as a parameter and assumes that the last string in the list is the file.
My problem
After I test this function, I delete the empty file (created only for the test purpose) and all the folders that my function creates. This is done using shutil.rmtree after the assert, and here lies the problem. When the test fails, it raises a AssertionError and those folders and files are not deleted because the code after the assert is not executed. This also sabotage the other tests because I use the same name of files and folders for all of them. Then I have to manually remove all those files to be able to test correctly again.
I thought of using fixtures but I don't think it is a good solution because, as I said, it test for different paths creation, it doesn't have a generic case. I would have to create individual fixtures for each test and this doesn't seem to be the best approach to this.
Here is one of my tests that that has this problem:
def test_alocate_file_three_level_path(root_path):
# creates files in root
file_path1 = os.path.join(root_path, 'test1.pdf')
Path(file_path1).touch()
# creates path for test
test_path = os.path.join(root_path, 'Downloads', 'path1', 'path2','path3','test1.pdf')
# function alocate the file to folders
func_aux.alocate_file('path1', 'path2', 'path3', 'test1.pdf')
# check if the file is there
assert os.path.isfile(test_path) == True
# remove the created file and folders
remove_path = os.path.join(root_path, 'Downloads', 'path1')
shutil.rmtree(remove_path)
I want to know if the only way I can guarantee that all my folders and files created for test purposes are deleted is using specific fixtures for each test or there is a way where I can execute always the code after the assert even with AssertionError
Solution
As @hoefling suggested, I implemented a fixture that creates a temporary directory. Modifying the code that I provided in the post, ended like this:
@pytest.fixture(scope="module")
def temp_dir(root_path):
down_path = os.path.join(root_path, 'Downloads', 'temp_dir')
os.makedirs(down_path)
yield down_path
shutil.rmtree(down_path)
def test_alocate_file_three_level_path(root_path, temp_dir):
# creates files in root
file_path1 = os.path.join(root_path, 'test1.pdf')
Path(file_path1).touch()
# creates path for test
test_path = os.path.join(temp_dir, 'path1', 'path2','path3','test1.pdf')
# function alocate the file to folders
func_aux.alocate_file('temp_dir', 'path1', 'path2', 'path3', 'test1.pdf')
# check if the file is there
assert os.path.isfile(test_path) == True
This garantee, in the end of the tests, that all the auxiliary files were deleted. For those who don't understand what is going on, the fixture is executed until the yield. After that, the tests receive its value and do its job. Independet of AssertionError, when the test end, it gets back to the fixture and run the code after the yield.
Answered By - CoolTarka
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.