3
\$\begingroup\$

If I have a number of different classes which manage certain tests. At the moment I have to launch each test individually which results in a lot of if statements.

I wonder if there is a way of putting all of these in a loop to manage the launching of each test and retrieving of results more cleanly. Does anyone have any advice? Can anyone improve on this? Is this use of classes optimal (I'm not a professional programmer)?

class Engine(object):
    """Class that holds information about the
tests relevant to the engine"""

    def __init__(self):
        self.run = True # Flag to run the test or not
        self.kg = 20.5 # Some information required by this test
        self.ok = 'Not run' # Final result to say if the test was passed

class Wheels(object):
    """Class that holds information about the
tests relevant to the wheels"""

    def __init__(self):
        self.run = True
        self.number = 4
        self.ok = 'Not run'

class Door(object):
    """Class that holds information about the
tests relevant to the doors"""

    def __init__(self):
        self.run = True
        self.colour = 'red'
        self.ok = 'Not run'

class Car(object):
    """Class that holds information about the
different tests available"""

    def __init__(self):
        self.engine = Engine()
        self.wheels = Wheels()
        self.door = Door()

motor = Car()

if motor.engine.on is True:
    import engine_tests # An external file containing everything about engine tests
    motor.engine.ok = engine_tests.launch(weight=motor.engine.kg) # Return success/failure of tests

if motor.wheels.on is True:
    import wheel_tests
    motor.wheels.ok = wheel_tests.launch(nwheels=motor.wheels.number)

if motor.door.on is True:
    import door_tests
    motor.door.ok = door_tests.launch(shading=motor.door.colour)

print 'Tests completed'
print 'Engine: ', motor.engine.ok
print 'Wheels: ', motor.wheels.ok
print 'Door: ', motor.door.ok
\$\endgroup\$
  • 2
    \$\begingroup\$ Could you give some more context? Are you testing software or an actual car? Why would you not run every test always? \$\endgroup\$ – Janne Karila Apr 25 '14 at 7:26
  • \$\begingroup\$ Janne, thanks for the comment. All tests would not be run every time, perhaps because computational resources are insufficient for certain tests at certain times, or one of the tests may have failed so I need to re-run that test without running all tests again. The "car" is only a representative example of a series of tests on an object, defined in classes like this. Does this make it clearer? \$\endgroup\$ – Gerhard Apr 25 '14 at 8:23
  • \$\begingroup\$ If you want to use loops to avoid duplicated code, you could store the car parts in a dictionnary : components = { 'Engine' : Engine(), 'Door' : Door(), } \$\endgroup\$ – SylvainD Apr 25 '14 at 9:22
3
\$\begingroup\$

The params for testing are different from each object, so I think this part should be put in the classes and present a uniform interface, this is what classes are about.

I suggest 2 versions: either you only put the params needed for test in the classes, or (better in my opinion), you put the entire call to the test in the classes. With some syntactic sugar, this leads to

Only the test data in the classes

class Engine(object):
    """Class that holds information about the
tests relevant to the engine"""

    def __init__(self):
        self.run = True # Flag to run the test or not
        self.kg = 20.5 # Some information required by this test
        self.ok = 'Not run' # Final result to say if the test was passed

    def get_test_params(self):
        return { 'weight': self.kg }

class Wheels(object):
    """Class that holds information about the
tests relevant to the wheels"""

    def __init__(self):
        self.run = True
        self.number = 4
        self.ok = 'Not run'

    def get_test_params(self):
        return { 'nwheels': self.number }

class Door(object):
    """Class that holds information about the
tests relevant to the doors"""

    def __init__(self):
        self.run = True
        self.colour = 'red'
        self.ok = 'Not run'

    def get_test_params(self):
        return { 'shading': self.colour }

class Car(object):
    """Class that holds information about the
different tests available"""

    def __init__(self):
        self.engine = Engine()
        self.wheels = Wheels()
        self.door = Door()

motor = Car()

for partName in 'engine wheels door'.split():
    part = getattr(motor, partName)
    part.on = True # So the test is run (everything is off in your example)
    if part.on: # No need to write "is True", this is what "if" is about
        test_module = __import__(partName + '_tests')
        part.ok = test_module.launch(**part.get_test_params())

print 'Tests completed'
print 'Engine: ', motor.engine.ok
print 'Wheels: ', motor.wheels.ok
print 'Door: ', motor.door.ok

Running the test from the classes

class Engine(object):
    """Class that holds information about the
tests relevant to the engine"""

    def __init__(self):
        self.run = True # Flag to run the test or not
        self.kg = 20.5 # Some information required by this test
        self.ok = 'Not run' # Final result to say if the test was passed

    def run_test(self):
        import engine_tests
        return engine_tests.launch(weight=self.kg)

class Wheels(object):
    """Class that holds information about the
tests relevant to the wheels"""

    def __init__(self):
        self.run = True
        self.number = 4
        self.ok = 'Not run'

    def run_test(self):
        import wheels_tests
        return wheels_tests.launch(nwheels=self.number)

class Door(object):
    """Class that holds information about the
tests relevant to the doors"""

    def __init__(self):
        self.run = True
        self.colour = 'red'
        self.ok = 'Not run'

    def run_test(self):
        import door_tests
        return door_tests.launch(shading=self.colour)

class Car(object):
    """Class that holds information about the
different tests available"""

    def __init__(self):
        self.engine = Engine()
        self.wheels = Wheels()
        self.door = Door()

motor = Car()

for partName in 'engine wheels door'.split():
    part = getattr(motor, partName)
    part.on = True # So the test is run (everything is off in your example)
    if part.on: # No need to write "is True", this is what "if" is about
        part.ok = part.run_test()

print 'Tests completed'
print 'Engine: ', motor.engine.ok
print 'Wheels: ', motor.wheels.ok
print 'Door: ', motor.door.ok

If there's only one car, the last part can become:

for part in (motor.engine, motor.wheels, motor.door):
    part.on = True # So the test is run (everything is off in your example)
    if part.on: # No need to write "is True", this is what "if" is about
        part.ok = part.run_test()
\$\endgroup\$
  • \$\begingroup\$ Thank you! These are two very elegant ways to do this, and this is very helpful. Thank you for taking the time to help improve my code. \$\endgroup\$ – Gerhard Apr 28 '14 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.