Let's talk about Tests
This week I continued with setting up some dependencies that would enhance my Site Generation program that I am writing, most notable among which was pytest.
I should mention here the reason I chose pytest is because of all of the testing methods in Python I found it was the simplest to actually write the tests in, being able to just directly pull whatever module you want to test, write a function with the test prefix and then assert simply using the keyword assert
.
I have grown quite fond of it and it's simplicity in the short time I have used it.
Getting Setup
To make things easier for future contributors I also added all my dependencies to a requirements text file and committed that to my repo as well.
I added pytest, coverage and pytest-cov
to my requirements, installed each and I configured them in a new file I created called pyproject.toml
on the root of my project.
The configuration looks as follows:
[tool.pytest.ini_options]
addopts = "-ra --cov"
testpaths = ["tests"]
pythonpath = ['src']
in this way the pytest
command when run from the directories belonging to the project will run all the tests from 'tests' which can be written with imports relative to 'src', with more information thanks to -ra and thanks to --cov along with coverage as well.
After running pytest
you have some captured coverage information that you can display in report format if you wish using coverage report
.
I would recommend using the -m
option with coverage report
as it will show you missing lines as well by number:
Of which I still have a lot, but I have covered the basics of my text to html conversion which I explain bellow.
Do get testy with me?
Testing is the focus of this week's changes and it has been a lot of changes actually.
Last week when I was linting I found that my program had "too many branches", this is pylint's way of saying it's not just written poorly, it's written very very poorly and everything is squished so closely together it's going to be difficult for people to make sense of it when first taking a look. In short, break it up, make it clearer, create smaller logical units of works. Make some more methods.
This week the same message came back across stronger when I started to try to write tests. I was doing a bunch of stuff in the same block of code so actually testing any individual piece of logic was a really daunting task. I didn't dwell too long on it, I realized my mistakes and what's done is done so I got to thinking what DO I want to test?
I started with what I thought was the simplest thing, I took the markdown conversion method my classmate Rudy initially had written for this project in a previous lab and I started by testing that. I found that the code that I had added for <hr> tags did not work exactly how I had intended and was eating some characters, I fixed that quickly and was glad I had gotten my first tests done.
The second task of the week was to
write at least one test that takes a simple piece of text and runs it through your parser, producing HTML output
I had written tests for a part of this process already, and so I thought to myself "What's next? What are the other things I am doing here in my linguini that I can factor out?"
A very important part of my code was the logic I was using to separate the lines of text coming in from the input file into the header if there was one and each respective paragraph that ensued after the header, if there was one.
I believe this logic was bundled together with opening and reading from a file at first but I thought to test it it would be a good idea to factor it out and allow it to work with a list of strings as a parameter.
This new method, line_by_line was the same logic I had before to wrap the correct tags around the correct portions of a list of strings but it now stood on its own which made it easier to test and it returns a tuple consisting of a list of strings that would form the body HTML and a Boolean value for whether there should be a title extracted from the header or whether there was no header at all (this is used in the following logic when writing everything to the final HTML).
After I factored the code out testing it was easier and I found some errors in the code, some instances where the paragraph tags were not being written correctly because I had not been paying close enough attention. These I fixed as well.
To keep things organized I created a separate file for testing each method, mardown_conversion and line_by_line seperately. All said, I had tested the basic functionality of the application, taking a list of strings (in practice read from a file) and the conversion of those string to HTML. The next part of my logic to test is inserting this into the HTML template that I have as an attribute of my SSJ class which I have recently also factored out into a separate method in order to make testing it more feasible, edit_template. It is entirely possible that by the due date of this lab I will have gone ahead and made another push doing so.
Wrapping it up
Through this process to this point I had already fixed a problem I had with <hr> tags in markdown conversion, a problem I had with the paragraph tags in certain cases and a problem I had with finding out whether I should use the first line as the title, none of which I knew I had to begin with.
It was eye opening how quickly problems began to surface with what I had written and I am sure that's really only the tip of the iceberg.
I also ended up pleasing pylint by factoring code into some smaller methods, and hopefully made my code clearer and better in general due to that.
Getting pretty close now.
When all of my tests were done and working, I added instructions into the CONTRIBUTING.md on how to use the testing setup that I had been using and I rebased, squashed, merged and pushed.
I will definitely continue testing in the future.
Testing commit:125c19f
Top comments (0)