Lutaaya Huzaifah Idris
Lutaaya Huzaifah Idris

Reputation: 3990

ValueError: not enough values to unpack while running unit tests Django ModelViewSet

Am testing an endpoint that retrieves data using a ModelViewSet, and am passing a param via a URL to it to get data but am getting this error when I run the unit tests:

   File "/Users/lutaayaidris/Documents/workspace/project_sample/project_sample/financing_settings/tests.py", line 195, in test_get_blocks
    self.block_get_data), content_type='application/json')
  File "/Users/lutaayaidris/Documents/workspace/project_sample/lib/python3.6/site-packages/rest_framework/test.py", line 286, in get
    response = super().get(path, data=data, **extra)
  File "/Users/lutaayaidris/Documents/workspace/project_sample/lib/python3.6/site-packages/rest_framework/test.py", line 194, in get
    'QUERY_STRING': urlencode(data or {}, doseq=True),
  File "/Users/lutaayaidris/Documents/workspace/project_sample/lib/python3.6/site-packages/django/utils/http.py", line 93, in urlencode
    for key, value in query:
ValueError: not enough values to unpack (expected 2, got 1)

This is how I have structured my tests , plus some dummy data for testing :

class TemplateData:

    """Template Mock data."""

    
    step_get_data = {
        "param": "step"
    }

    block_get_data = {
        "param": "block"
    }

    get_no_data = {
        "param_": "block"
    }


class TemplateViewTests(TestCase, TemplateData):

    """Template Tests (Block & Step)."""

    def setUp(self):
        """
        Initialize client,  Step and Block id and data created.
        """
        self.client = APIClient()
        self.block_id = 0
        self.step_id = 0
        self.create_block_step_data()

    def create_block_step_data(self):
        """Create ProcessVersion, Step, & Block mock data."""
        self.process_version = ProcessVersion.objects.create(
            tag="TESTING_TAG",
            is_process_template=False,
            status="IN EDITING",
            attr_map="TESTING_ATTR",
            loan_options=None
        )

        self.step = Step.objects.create(
            version=self.process_version,
            is_process_template=True,
            title="TESTING",
            help_text="TESTING",
            order=1,
            slug="slug",
            can_be_duplicated=False,
            max_duplicated_number=2,
        )

        self.step_id = self.step.pk

        self.block_id = Block.objects.create(
            step=self.step,
            is_process_template=True,
            title="TESTING",
            information_text="This is  testing "
                             "information",
            order=1,
            depending_field="depending_field",
            visibility_value="visibility_value",
            slug="slug",
            can_be_duplicated=False,
            max_duplicated_number=2,
            ).pk

        self.process_version_1 = ProcessVersion.objects.create(
            tag="TESTING_TAG",
            is_process_template=False,
            status="IN EDITING",
            attr_map="TESTING_ATTR",
            loan_options=None
        )

        self.step_1 = Step.objects.create(
            version=self.process_version_1,
            is_process_template=True,
            title="TESTING",
            help_text="TESTING",
            order=1,
            slug="slug",
            can_be_duplicated=False,
            max_duplicated_number=2,
        )

        self.block_1 = Block.objects.create(
            step=self.step,
            is_process_template=True,
            title="TESTING",
            information_text="This is  testing "
                             "information",
            order=1,
            depending_field="depending_field",
            visibility_value="visibility_value",
            slug="slug",
            can_be_duplicated=False,
            max_duplicated_number=2,
        ).pk

    def test_get_blocks(self):
        """Test get list of Block. """
        response = self.client.get(
            "/api/v1/financing-settings/template/",
            data=json.dumps(
                self.block_get_data), content_type='application/json')
        self.assertEqual(response.status_code, 200)

    def test_get_steps(self):
        """Test get list of Step. """
        response = self.client.get(
            "/api/v1/financing-settings/template/",
            data=json.dumps(
            self.block_get_data),
            content_type='application/json')
        self.assertEqual(response.status_code, 200)

    def test_no_step_or_block(self):
        """Test get no list of Step or Block. """
        response = self.client.get(
            "/api/v1/financing-settings/template/",
           data=json.dumps(
            self.block_get_data),
            content_type='application/json')
        self.assertEqual(response.status_code, 204)

As you can see above those are my tests, I have already setup the data , now I want to retrieve back the data, but because of the exception above I can't.

Lastly, in my endpoint implementation, I used a Viewset to handle this , below is the code :

class TemplateView(ModelViewSet):
    """ViewSet for Saving Block/ Step template."""

    
    def list(self, request, *args, **kwargs):

        """Get list of Block/Steps with is_process_template is equal to True."""
        param = request.data['param']

        if param == "block":
            _block = Block.objects.filter(is_process_template=True).values()
            return JsonResponse({"data": list(_block)}, safe=False, status=200)

        elif param == "step":
            _step = Step.objects.filter(is_process_template=True)
            return JsonResponse({"data": list(_step)}, safe=False, status=200)

        return Response(status=status.HTTP_204_NO_CONTENT)

What is causing this , in my understanding I feel like everything should work.

Upvotes: 1

Views: 941

Answers (2)

franjial
franjial

Reputation: 33

The function Client.get expect a dictionary as data argument and try to encode it in the url using the function urlencode. You could do something like that:

from django.test import Client
c = Client()
block_get_data = {
    "param": "block"
}
c.get('path', block_get_data)

block_get_data will be sent in the url as 'param=block'

If you want to send JSON formated data in a GET method, you can use Client.generic function as follow:

from django.test import Client
import json

c = Client()
block_get_data = {
    "param": "block"
}
c.generic('GET', 'path', json.dumps(block_get_data), 'application/json')

Upvotes: 1

Sohaib
Sohaib

Reputation: 594

You are facing this error because this dict

block_get_data = {
        "param": "block"
    }

you are trying to use it in this way

for key,val in block_get_data

and it will produce the error like

for key,val in block_get_data:
ValueError: too many values to unpack (expected 2)

It will be solved if your loop through dict by using .items() method.

for key,val in block_get_data.items():

I think by passing parameter as self.block_get_data.items() may solve your problem.

Upvotes: 0

Related Questions