Muthu Kumar
Muthu Kumar

Reputation: 945

Django : How to upload csv file in unit test case using APIClient

I would like to write a unit test for a view on a Django REST Framework application. The test should upload a CSV file using the POST.

@staticmethod
def _file_upload(client, string, args, file_name):
    base_path = os.path.dirname(os.path.realpath(__file__))
    with open(base_path + file_name, 'rb') as data:
        data = {
                'file': data
            }
        response = client.post(reverse(string, args=[args]), data, format = "multipart")
    return response.status_code, response.data

The above code I used which obviously doesn't work it shows the following error

Missing filename. Request should include a Content-Disposition header with a filename parameter.

The following code is the one that I want to test via unit testing.

class ChartOfAccounts(views.APIView):
     parser_classes = (JSONParser, FileUploadParser)
     def post(self, request, pk, *args, **kwargs):
        request.FILES['file'].seek(0)
        csv_data = CSVUtils.format_request_csv(request.FILES['file'])
        try:
            coa_data = CSVUtils.process_chart_of_accounts_csv(company, csv_data)
            serializer = CoASerializer(coa_data, many=True)
            if len(serializer.data) > 0:
                return Utils.dispatch_success(request, serializer.data)

        except Exception as e:
            error = ["%s" % e]
            return Utils.dispatch_failure(request, 'DATA_PARSING_ISSUE', error)

Any help regarding this is welcome. Thanks in advance

Upvotes: 1

Views: 3250

Answers (2)

rounak tadvi
rounak tadvi

Reputation: 29

Here's what i did

@patch("pandas.read_csv")
@patch("pandas.DataFrame.to_sql")
def test_upload_csv_success(self, mock_read_csv, mock_to_sql) -> None:
    """Test uploading a csv file"""
    file_name = "test.csv"
    # Open file in write mode (Arrange)
    with open(file_name, "w") as file:
        writer = csv.writer(file)
        # Add some rows in csv file
        writer.writerow(["name", "area", "country_code2", "country_code3"])
        writer.writerow(
            ["Albania", 28748, "AL", "ALB"],
        )
        writer.writerow(
            ["Algeria", 2381741, "DZ", "DZA"],
        )
        writer.writerow(
            ["Andorra", 468, "AD", "AND"],
        )
    # open file in read mode
    data = open(file_name, "rb")
    # Create a simple uploaded file
    data = SimpleUploadedFile(
        content=data.read(), name=data.name, content_type="multipart/form-data"
    )

    # Perform put request (Act)
    res = self.client.put(CSV_URL, {"file_name": data}, format="multipart")
    # Mock read_csv() and to_sql() functions provided by pandas module
    mock_read_csv.return_value = True
    mock_to_sql.return_value = True

    # Assert
    self.assertEqual(res.status_code, status.HTTP_201_CREATED)
    self.assertEqual(res.data, "Data set uploaded")
    # Delete the test csv file
    os.remove(file_name)

Upvotes: 0

Muthu Kumar
Muthu Kumar

Reputation: 945

I have fixed my issue using the different approach with HTTP headers HTTP_CONTENT_DISPOSITION, HTTP_CONTENT_TYPE by this reference

And here is my code

@staticmethod
def _file_upload_csv( string, args, file_name):

    base_path = os.path.dirname(os.path.realpath(__file__))
    data = open(base_path + file_name, 'rb')

    data = SimpleUploadedFile(content = data.read(),name = data.name,content_type='multipart/form-data')

    factory = RequestFactory()
    user = User.objects.get(username=UserConstant.ADMIN_USERNAME)

    view = ChartOfAccounts.as_view()

    content_type = 'multipart/form-data'
    headers= {
        'HTTP_CONTENT_TYPE': content_type,
        'HTTP_CONTENT_DISPOSITION': 'attachment; filename='+file_name}

    request = factory.post(reverse(string, args=[args]),{'file': data},
                           **headers)

    force_authenticate(request, user=user)
    response = view(request, args)

    return response.status_code, response.data

**headers done the trick...

Upvotes: 4

Related Questions