Reputation: 1192
My pytest unit test keeps returning the error ModuleNotFoundError: No module name billing
.
Oddly enough the send_invoices
method in the billing module is able to be called when I remove the patch statement. Why is mock.patch unable to find the billing module and patch the method if this is the case?
billing.py
import pdfkit
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from projectxapp.models import User
Class Billing:
#creates a pdf of invoice. Takes an invoice dictionary
def create_invoice_pdf(self, invoice, user_id):
#get the html of the invoice
file_path ='/{}-{}.pdf'.format(user_id, invoice['billing_period'])
invoice_html = render_to_string('templates/invoice.html', invoice)
pdf = pdfkit.from_file(invoice_html, file_path)
return file_path, pdf
#sends invoice to customer
def send_invoices(self, invoices):
for user_id, invoice in invoices.items():
#get customers email
email = User.objects.get(id=user_id).email
billing_period = invoice['billing_period']
invoice_pdf = self.create_invoice_pdf(invoice, user_id)
email = EmailMessage(
'Statement of credit: {}-{}'.format(user_id, billing_period),
'Attached is your statement of credit.\
This may also be viewed on your dashboard when you login.',
'[email protected]',
[email],
).attach(invoice_pdf)
email.send(fail_silently=False)
return True
test.py
from mock import patch
from projectxapp import billing
@pytest.mark.django_db
def test_send_invoice():
invoices = {
1: {
'transaction_processing_fee': 2.00,
'service_fee': 10.00,
'billing_period': '2020-01-02'
},
2: {
'transaction_processing_fee': 4.00,
'service_fee': 20.00,
'billing_period': '2020-01-02'
}
}
with patch('services.billing.Billing().create_invoice_pdf') as p1:
p1.return_value = '/invoice.pdf'
test = billing.Billing().send_invoices(invoices)
assert test == True
Upvotes: 8
Views: 21142
Reputation: 164
Sometimes its just the name of the file that is wrong. Checkout the names of the files and ensure that they are same as required by the decorater.
Upvotes: 1
Reputation: 3869
Since, this is the first google hit for ModuleNotFoundError with patch...
In my case, it was an issue with the letter case (com.foo.SftpClient instead of com.foo.SFTPClient)
In my env (python 3.6), the interpreter complained that com.foo module could not be found even though the actual reason was a typo in the class name
Upvotes: -1
Reputation: 1192
Since I had already imported the module of the method I needed to patch. I didn't need to use the full path including the package name.
Changed
patch('projectxapp.billing.Billing.create_invoice_pdf')
to this
patch('billing.Billing.create_invoice_pdf')
From the unittest documentation:
target should be a string in the form 'package.module.ClassName'. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch() from. The target is imported when the decorated function is executed, not at decoration time.
Upvotes: 5
Reputation: 106553
You should specify the full path to the module, including the package names, when you use patch
. Also, do not use parentheses in the path. Modify the return_value
attribute of the Mock
object to customize the returning value of a call to the object:
with patch('projectxapp.billing.Billing.create_invoice_pdf') as p1:
p1.return_value = '/invoice.pdf'
test = billing.Billing().send_invoices(invoices)
Upvotes: 11