I’m starting with simple calculations and tests. I’m confused with writing tests.
I wrote a test_negative_hours
here are my modified files: test_time_log.py
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
import unittest
from erpnext.projects.doctype.time_log.time_log import OverlapError
from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
class TestTimeLog(unittest.TestCase):
def test_duplication(self):
frappe.db.sql("delete from `tabTime Log`")
frappe.get_doc(frappe.copy_doc(test_records[0])).insert()
ts = frappe.get_doc(frappe.copy_doc(test_records[0]))
self.assertRaises(OverlapError, ts.insert)
frappe.db.sql("delete from `tabTime Log`")
def test_negative_hours(self):
frappe.db.sql("delete from `tabTime Log`")
test_time_log = frappe.new_doc("Time Log")
test_time_log.activity_type = "Communication"
test_time_log.from_time = "2013-01-01 11:00:00.000000"
test_time_log.to_time = "2013-01-01 10:00:00.000000"
test_time_log.save()
self.assertRaises(frappe.ValidationError, test_time_log.save)
frappe.db.sql("delete from `tabTime Log`")
test_records = frappe.get_test_records('Time Log')
test_ignore = ["Time Log Batch", "Sales Invoice"]
then I ran test:
revant@revant-laptop:~/frappe-bench$ bench frappe --run_tests -d "Time Log"
.F.
======================================================================
FAIL: test_negative_hours (erpnext.projects.doctype.time_log.test_time_log.TestTimeLog)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/revant/frappe-bench/apps/erpnext/erpnext/projects/doctype/time_log/test_time_log.py", line 27, in test_negative_hours
self.assertRaises(frappe.ValidationError, test_time_log.save)
AssertionError: ValidationError not raised
----------------------------------------------------------------------
Ran 3 tests in 0.455s
FAILED (failures=1)
<unittest.runner.TextTestResult run=3 errors=0 failures=1>
Then I modified time_log.py:
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr, comma_and
class OverlapError(frappe.ValidationError): pass
from frappe.model.document import Document
class TimeLog(Document):
def validate(self):
self.set_status()
self.validate_overlap()
self.calculate_total_hours()
def calculate_total_hours(self):
from frappe.utils import time_diff_in_hours
self.hours = time_diff_in_hours(self.to_time, self.from_time)
# I added this if
if self.hours < 0:
frappe.throw(_("\'From Time\' cannot be later than \'To Time\'"))
def set_status(self):
self.status = {
0: "Draft",
1: "Submitted",
2: "Cancelled"
}[self.docstatus or 0]
if self.time_log_batch:
self.status="Batched for Billing"
if self.sales_invoice:
self.status="Billed"
def validate_overlap(self):
existing = frappe.db.sql_list("""select name from `tabTime Log` where owner=%s and
(
(from_time between %s and %s) or
(to_time between %s and %s) or
(%s between from_time and to_time))
and name!=%s
and ifnull(task, "")=%s
and docstatus < 2""",
(self.owner, self.from_time, self.to_time, self.from_time,
self.to_time, self.from_time, self.name or "No Name",
cstr(self.task)))
if existing:
frappe.throw(_("This Time Log conflicts with {0}").format(comma_and(existing)), OverlapError)
def before_cancel(self):
self.set_status()
def before_update_after_submit(self):
self.set_status()
@frappe.whitelist()
def get_events(start, end):
from frappe.widgets.reportview import build_match_conditions
if not frappe.has_permission("Time Log"):
frappe.msgprint(_("No Permission"), raise_exception=1)
match = build_match_conditions("Time Log")
data = frappe.db.sql("""select name, from_time, to_time,
activity_type, task, project from `tabTime Log`
where from_time between '%(start)s' and '%(end)s' or to_time between '%(start)s' and '%(end)s'
%(match)s""" % {
"start": start,
"end": end,
"match": match and (" and " + match) or ""
}, as_dict=True, update={"allDay": 0})
for d in data:
d.title = d.name + ": " + (d.activity_type or "[Activity Type not set]")
if d.task:
d.title += " for Task: " + d.task
if d.project:
d.title += " for Project: " + d.project
return data
I ran test again and got:
ValidationError: 'From Time' cannot be later than 'To Time'
----------------------------------------------------------------------
Ran 3 tests in 0.471s
FAILED (errors=1)
<unittest.runner.TextTestResult run=3 errors=1 failures=0>
Now I’m confused,
It doesnt let me save negative hours in Time log as expected.
How to pass the test? I’m not understanding writing test.