3
\$\begingroup\$

I have a list of input, a greedy method and a dynamic programming method. I wrote a unittest script to test my two methods with input list but I don't know if I'm writing it right:

import unittest
from land_selling import Offer, Seller


class LandSellingTest(unittest.TestCase):
    offers1 = [
        Offer(0, 6, 2),
        Offer(1, 2, 4),
        Offer(3, 5, 1),
        Offer(5, 9, 3),
        Offer(7, 10, 2),
        Offer(10, 20, 5),
        Offer(34, 2, 1)
    ]
    offers2 = [
        Offer(6, 10, 4),
        Offer(1, 5, 2),
        Offer(7, 20, 3),
        Offer(2, 7, 1),
        Offer(14, 30, 2),
        Offer(3, 6, 3),
        Offer(8, 15, 2),
        Offer(20, 35, 5),
        Offer(25, 5, 3)
    ]
    offers3 = [
        Offer(17, 1, 12),
        Offer(7, 2, 10),
        Offer(17, 2, 8),
        Offer(20, 3, 6),
        Offer(3, 11, 4),
        Offer(22, 12, 2)
    ]

    // input list
    global offers_list
    offers_list = [offers1, offers2, offers3]

    // greedy output list
    global greedy_answers
    greedy_answers = [4, 3, 2]

    // dynamic output list
    global dynamic_answers
    dynamic_answers = [13, 12, 16]

    @classmethod
    def setUpClass(self):
        self.offers_list = offers_list
        self.greedy_answers = greedy_answers
        self.dynamic_answers = dynamic_answers

    def test_greedy(self):
        for offers, ans in zip(self.offers_list, self.greedy_answers):
            seller = Seller(offers)
            seller.set_up()
            self.assertEqual(len(seller.accepted_offers()), ans)

    def test_dynamic(self):
        for offers, ans in zip(self.offers_list,self.dynamic_answers):
            seller = Seller(offers)
            seller.sort_offers_by_finish()
            self.assertEqual(seller.maximum_profit(), ans)

if __name__ == '__main__':
    unittest.main()
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Using py.test with scenarios

Instead of using unittest, I prefer using pytest. There are few reasons:

  • no need for using test classes
  • test cases are easy to write as very simple functions
  • any inputs to test can be parametrized and easily fed by fixtures or parametrization
  • very easy to have one test case run for one combinations of parameters - makes easier to identify how large is the share of failing cases.

Here is my rewrite to pytest (all put in one file test_it.py:

Imports:

import pytest
from land_selling import Offer, Seller

Function generating scenarios:

def gen_scenarios(mode):
    assert mode in ["greedy", "dynamic"]

    offers1 = [
        Offer(0, 6, 2),
        Offer(1, 2, 4),
        Offer(3, 5, 1),
        Offer(5, 9, 3),
        Offer(7, 10, 2),
        Offer(10, 20, 5),
        Offer(34, 2, 1)
    ]
    offers2 = [
        Offer(6, 10, 4),
        Offer(1, 5, 2),
        Offer(7, 20, 3),
        Offer(2, 7, 1),
        Offer(14, 30, 2),
        Offer(3, 6, 3),
        Offer(8, 15, 2),
        Offer(20, 35, 5),
        Offer(25, 5, 3)
    ]
    offers3 = [
        Offer(17, 1, 12),
        Offer(7, 2, 10),
        Offer(17, 2, 8),
        Offer(20, 3, 6),
        Offer(3, 11, 4),
        Offer(22, 12, 2)
    ]

    # input list
    offers_list = [offers1, offers2, offers3]

    if mode == "greedy":
        greedy_answers = [4, 3, 2]
        return zip(offers_list, greedy_answers)
    elif mode == "dynamic":
        dynamic_answers = [13, 12, 16]
        return zip(offers_list, dynamic_answers)

Parametrized tests:

@pytest.mark.parametrize("scenario", gen_scenarios("greedy"))
def test_greedy(scenario):
    offers, ans = scenario
    seller = Seller(offers)
    seller.set_up()
    assert len(seller.accepted_offers()) == ans


@pytest.mark.parametrize("scenario", gen_scenarios("dynamic"))
def test_dynamic(scenario):
    offers, ans = scenario
    seller = Seller(offers)
    seller.sort_offers_by_finish()
    assert seller.maximum_profit() == ans

Run it by:

$ py.test -sv test_it.py

I cannot provide sample output as I do not have access to the imported code, but there you will see another beauty of py.test - really well readable test output.

\$\endgroup\$
2
\$\begingroup\$

I would use setUp instead of setUpClass. In your case the effect might be the same, but it's better to setup the input data per test method, not test case class:

import unittest
from land_selling import Offer, Seller


class LandSellingTest(unittest.TestCase):

    def setUp(self):
        offers1 = [
            Offer(0, 6, 2),
            Offer(1, 2, 4),
            Offer(3, 5, 1),
            Offer(5, 9, 3),
            Offer(7, 10, 2),
            Offer(10, 20, 5),
            Offer(34, 2, 1)
        ]
        offers2 = [
            Offer(6, 10, 4),
            Offer(1, 5, 2),
            Offer(7, 20, 3),
            Offer(2, 7, 1),
            Offer(14, 30, 2),
            Offer(3, 6, 3),
            Offer(8, 15, 2),
            Offer(20, 35, 5),
            Offer(25, 5, 3)
        ]
        offers3 = [
            Offer(17, 1, 12),
            Offer(7, 2, 10),
            Offer(17, 2, 8),
            Offer(20, 3, 6),
            Offer(3, 11, 4),
            Offer(22, 12, 2)
        ]
        # input list
        self.offers_list = [offers1, offers2, offers3]

        # greedy output list
        self.greedy_answers = [4, 3, 2]

        # dynamic output list
        self.dynamic_answers = [13, 12, 16]

    def test_greedy(self):
        ...

If your intention is to create the test data globally, just do:

import unittest
from land_selling import Offer, Seller


offers1 = [
    Offer(0, 6, 2),
    Offer(1, 2, 4),
    Offer(3, 5, 1),
    Offer(5, 9, 3),
    Offer(7, 10, 2),
    Offer(10, 20, 5),
    Offer(34, 2, 1)
]
offers2 = [
    Offer(6, 10, 4),
    Offer(1, 5, 2),
    Offer(7, 20, 3),
    Offer(2, 7, 1),
    Offer(14, 30, 2),
    Offer(3, 6, 3),
    Offer(8, 15, 2),
    Offer(20, 35, 5),
    Offer(25, 5, 3)
]
offers3 = [
    Offer(17, 1, 12),
    Offer(7, 2, 10),
    Offer(17, 2, 8),
    Offer(20, 3, 6),
    Offer(3, 11, 4),
    Offer(22, 12, 2)
]

# input list
offers_list = [offers1, offers2, offers3]

# greedy output list
greedy_answers = [4, 3, 2]

# dynamic output list
dynamic_answers = [13, 12, 16]


class LandSellingTest(unittest.TestCase):

    def setUp(self):
        self.offers_list = offers_list
        self.greedy_answers = greedy_answers
        self.dynamic_answers = dynamic_answers

    def test_greedy(self):
        ...
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.