I have 2 classes that are identical aside from their inheritance. Each class overrides the same methods. I tried to avoid redundancy by using a common global method, but it wasn't enough to avoid a JSCPD error.
I'm not quite sure how to arrange things so that I only have 1 instance of the over-ridden methods, but each over-riding the methods of different base classes...
Probably if I removed the doc strings (which I've removed below), I'd avoid the linting error, but I'd prefer knowing how to accomplish this correctly.
import time
from django.test import TestCase, TransactionTestCase
LONG_TEST_THRESH_SECS = 20
LONG_TEST_ALERT_STR = f" [ALERT > {LONG_TEST_THRESH_SECS}]"
class TracebaseTestCase(TestCase):
maxDiff = None
databases = "__all__"
def setUp(self):
self.testStartTime = time.time()
def tearDown(self):
_reportRunTime(self.id(), self.testStartTime)
def setUpClass(self):
self.classStartTime = time.time()
def setUpTestData(self):
_reportRunTime(f"{self.__class__.__name__}.setUpTestData", self.classStartTime)
class Meta:
abstract = True
class TracebaseTransactionTestCase(TransactionTestCase):
maxDiff = None
databases = "__all__"
def setUp(self):
self.testStartTime = time.time()
def tearDown(self):
_reportRunTime(self.id(), self.testStartTime)
def setUpClass(self):
self.classStartTime = time.time()
def setUpTestData(self):
_reportRunTime(f"{self.__class__.__name__}.setUpTestData", self.classStartTime)
class Meta:
abstract = True
def _reportRunTime(id, startTime):
t = time.time() - startTime
heads_up = "" # String to include for tests that run too long
if t > LONG_TEST_THRESH_SECS:
heads_up = LONG_TEST_ALERT_STR
print("TEST TIME%s: %s: %.3f" % (heads_up, id, t))
I have a vague recollection back in my C++ school days about creating classes where you could supply a class as input for it's "inheritance" but I don't remember what that was called. I recall it used angle brackets in its declaration. I feel like that's what I need. Something like:
class abstractBaseClass(<base class input>):
# This would be where the methods would be defined
# I would also make reportRunTime be a member function here if I knew how to implement this "class template"
class TracebaseTestCase(abstractBaseClass(TestCase))
pass
class TracebaseTransactionTestCase(abstractBaseClass(TransactionTestCase))
pass
Am I close?
UPDATE: I fleshed out the rest of my source code, since there seemed to be some question about if it would affect the answer.
The point is that in each case, I am either over-riding the methods of TestCase or TransactionTestCase. And wherever I inherit from (for example) TracebaseTestCase, TestCase is determining when to run setUp, tearDown, setUpClass, and setUpTestData.
The code works as it is. I just want to avoid the jscpd linting error and reduce the redundancy.
You might consider using a mix-in.
class TestSkeleton:
maxDiff = None
databases = "__all__"
def setUp(self):
self.testStartTime = time.time()
def tearDown(self):
_reportRunTime(self.id(), self.testStartTime)
def setUpClass(self):
self.classStartTime = time.time()
def setUpTestData(self):
_reportRunTime(f"{self.__class__.__name__}.setUpTestData", self.classStartTime)
class Meta:
abstract = True
class TracebaseTestCase(TestSkeleton, TestCase):
pass
class TracebaseTransactionTestCase(TestSkeleton, TransactionTestCase):
pass
tearDown
and setUpTestData
probably need some adjustment depending on exactly what _reportRunTime
is and what it's first argument is supposed to represent.