[Tutor] Writing unit tests that involve email

Arnel Legaspi jalespring at gmail.com
Wed Jul 17 07:14:28 CEST 2013


Steven D'Aprano <steve <at> pearwood.info> writes:
> 
> On 17/07/13 13:34, Arnel Legaspi wrote:
> 
> > the trouble I have is on making the unit tests run such that
> > it
> > will force the script I'm testing to send the email. If I just use the
> > script
> > on my own, it does send the emails, no problem. With the unit tests I've
> > written, it's not doing so.
> 
> How does your script send emails? At some place, there will be something
> that effectively does the following steps:
> 
> * build email
> * send email
> 
> I recommend that your script has a function that does each: somewhere you
> have something that says
> 
> def build_email_body(arg1, arg2, arg3):
>      ...
> 
> def send_email(body):
>      ...
>
> Then you can test each separately. In your unit tests, you just call
> build_email_body and sees if it returns the correct data, no sending
> required; and then you call send_email and see that it actually sends an
> email.

The script does have a send_post() function that essentially builds the 
email
message itself, along with the necessary headers, and runs the
smtplib.SMTP_SSL() method to send the whole thing off to the SMTP server.

Should I factor each component out of the send_post() function to test for 
them
separately, or just leave it as is? Is it better to do so?

> Oh, all of this assumes that the unit test imports your script! This makes
> it critical that your script includes something like this at the end:
> 
> def run():  # or "main", if you prefer
>      # script logic goes in here
> 
> if __name__ == '__main__':
>      run()
> 
> Then your tests can import the script without it automatically running.

So it does come down to importing the script methods *inside* the unit 
tests. I
thought it was done otherwise.

In the unit tests, I have methods that clears the arguments given to the 
script
(clear_args()) and replaces them with the ones created by the setUp() method
(add_testfiles()). I do have a run() function which gets the arguments, and
runs the send_post() function.

I guess I'll have to try and see whether it's enough for the script to run 
with
the unit-test-supplied arguments and probably just add something like:

import downpost

...

class TestReadingSendingPostFile(unittest.TestCase):
    
    def setUp():
        ...
    
    def test_sendpost(self):
        clear_args()
        add_testfiles()
        downpost.run()
        
All right, Steven. Thanks for the nudge in the right direction!


--Arnel



More information about the Tutor mailing list