0

I'm working on a flask application and I'm using marshmallow to validate and "cast" values when someone hit an endpoint, everything works as expected but now I need to write some unit tests for the marshmallow schema that I wrote. Some methods have @validates and @post_load and other don't

class MultipartFileSchema(ma.Schema):
    data = ma.fields.Raw(required=True, load_only=True)
    accepted_fields = ma.fields.List(ma.fields.Dict, required=False, default=[])
    logger = logging.getLogger(__name__)

    @validates("data")
    def is_file_valid(self, files: FileStorage) -> None:
        """Check if the file uploaded is valid"""
        self.logger.info("Validating CSV file attached to the request in 'data' field")
        if isinstance(files, FileStorage):
            # Mypy is complaining about the following line, it says that that files is None type,
            # but it is not, it is a FileStorage object, since it passes the isinstance check
            if files.filename.endswith(".csv"):  # type: ignore
                content = files.readline().decode("utf-8")
                if content:
                    for field in content.split(","):
                        if not self.is_sp_key_valid(field.split(".")):
                            raise ValidationError(message="Invalid fields")
                else:
                    raise ValidationError(message="Invalid/Missing file content")
                files.seek(0)
            else:
                raise ValidationError("Invalid file type")
        elif not isinstance(files, FileStorage):
            raise ValidationError("Invalid/Missing file content")

    @post_load
    def load_file(self, files, many, **kwargs) -> dict:
        """Load the file and return a dict with the file content"""
        self.logger.info("Converting CSV file to a dict")
        files["accepted_fields"] = []
        content = StringIO(files["data"].read().decode("utf-8"))
        csv_raw_data = csv.DictReader(content, delimiter=",")

        for row in csv_raw_data:
            service_provider_raw: dict[str, dict[str, Union[str, bool, int]]] = {}

            for key, value in row.items():
                key_list = key.split(".")
                sp_main_key = key_list[0]
                sp_sub_key = key_list[1]
                if sp_main_key not in service_provider_raw:
                    service_provider_raw[sp_main_key] = {}
                service_provider_raw[sp_main_key][sp_sub_key] = value

            service_provider = CreateUpdateServiceProviderSchema().load(service_provider_raw)

            files["accepted_fields"].append(service_provider)

        return files

    def is_sp_sub_key_valid(self, sp_main_key: str, sp_sub_key: str) -> bool:
        """Check if the sub key in a service_provider object is valid"""
        self.logger.info("Validating sub keys in service_provider object")
        valid = False
        if sp_main_key == "general_fields":
            valid = sp_sub_key in ["name", "service_provider_type", "status"]
        elif sp_main_key == "primary_contact":
            valid = sp_sub_key in ["email_address", "phone_number"]
        elif sp_main_key == "address":
            valid = sp_sub_key in [
                "street",
                "city",
                "state",
                "country",
                "zip_code",
            ]
        return valid

    def is_sp_key_valid(self, key_list: list[str]) -> bool:
        """Check if the key in a service_provider object is valid"""
        self.logger.info("Validating dict is a valid service_provider object")
        valid = True
        if len(key_list) == 2:
            sp_main_key = key_list[0].strip()
            sp_sub_key = key_list[1].strip()
            if not self.is_sp_sub_key_valid(sp_main_key, sp_sub_key):
                valid = False
        else:
            valid = False
        return valid

so the question is how can I test those methods individully, specially those with decorator? thanks in advance for the help! :-)

juanp_1982
  • 917
  • 2
  • 16
  • 37

0 Answers0