Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Test Coverage with Pytest #165

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[run]

omit =
*cot*
*iibb*
*nsis*
*/padron.py
Expand Down
11 changes: 10 additions & 1 deletion recex1.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import traceback

# revisar la instalación de pyafip.ws:
from pyafipws.wsaa import WSAA
from pyafipws import wsfexv1
from pyafipws.utils import SimpleXMLElement, SoapClient, SoapFault, date
from pyafipws.utils import leer, escribir, leer_dbf, guardar_dbf, N, A, I, abrir_conf
Expand Down Expand Up @@ -333,10 +334,18 @@ def main():

if config.has_option("WSFEXv1", "TIMEOUT"):
TIMEOUT = int(config.get("WSFEXv1", "TIMEOUT"))

# This change handles the case where 'proxy_port' may not be present in the config.
# It ensures that we only try to convert 'proxy_port' to an integer if it exists,
# preventing KeyError exceptions and making the code more robust to different
# configuration scenarios. This modification allows the function to work with
# or without proxy settings, improving its flexibility and error handling.

if config.has_section("PROXY") and not HOMO:
proxy_dict = dict(("proxy_%s" % k, v) for k, v in config.items("PROXY"))
proxy_dict["proxy_port"] = int(proxy_dict["proxy_port"])
if "proxy_port" in proxy_dict:
proxy_dict["proxy_port"] = int(proxy_dict["proxy_port"])

else:
proxy_dict = {}

Expand Down
268 changes: 268 additions & 0 deletions tests/test_cot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
#!/usr/bin/python
# -*- coding: utf8 -*-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.

"""Test para cot"""

__author__ = "Mariano Reingart <reingart@gmail.com>"
__copyright__ = "Copyright (C) 2010-2019 Mariano Reingart"
__license__ = "GPL 3.0"

"""Test the COT (Comprobante de Operaciones en Tránsito) module.

This module contains tests for the COT class, which is used to interact with the
AFIP COT web service. The tests cover various scenarios, including connecting
to the service, presenting remitos, reading validation responses, and handling
errors.
"""

import pytest
from pyafipws.cot import COT, INSTALL_DIR, __version__, HOMO
from pysimplesoap.simplexml import SimpleXMLElement


@pytest.fixture
def cot_instance():
"""Fixture to create a COT instance for testing."""
return COT()


@pytest.mark.dontusefix
def test_conectar_with_error(cot_instance):
"""
Test the Conectar method with invalid parameters.
Expects an exception to be raised.
"""
with pytest.raises(Exception):
cot_instance.Conectar(url="invalid_url", proxy="invalid_proxy")


@pytest.mark.dontusefix
def test_presentar_remito_with_file_not_found(cot_instance, monkeypatch):
"""
Test PresentarRemito method when the file is not found.
Expects the method to return False and set an appropriate error message.
"""
monkeypatch.setattr("os.path.exists", lambda x: False)
result = cot_instance.PresentarRemito("non_existent_file.txt")
assert result is False
assert "Archivo no encontrado" in cot_instance.Excepcion


@pytest.mark.dontusefix
def test_leer_validacion_remito(cot_instance):
"""
Test LeerValidacionRemito method.
Checks if the method correctly reads and sets remito validation data.
"""
cot_instance.remitos = [
{
"NumeroUnico": "123",
"Procesado": "SI",
"COT": "COT123",
"Errores": [("E001", "Error 1")],
}
]
assert cot_instance.LeerValidacionRemito() is True
assert cot_instance.NumeroUnico == "123"
assert cot_instance.Procesado == "SI"
assert cot_instance.COT == "COT123"
assert cot_instance.LeerValidacionRemito() is False


@pytest.mark.dontusefix
def test_leer_error_validacion(cot_instance):
"""
Test LeerErrorValidacion method.
Verifies if the method correctly reads and sets error validation data.
"""
cot_instance.errores = [("E001", "Error 1"), ("E002", "Error 2")]
assert cot_instance.LeerErrorValidacion() is True
assert cot_instance.CodigoError == "E002"
assert cot_instance.MensajeError == "Error 2"
assert cot_instance.LeerErrorValidacion() is True
assert cot_instance.CodigoError == "E001"
assert cot_instance.MensajeError == "Error 1"
assert cot_instance.LeerErrorValidacion() is False


@pytest.mark.dontusefix
def test_analizar_xml_with_invalid_xml(cot_instance):
"""
Test AnalizarXml method with invalid XML.
Expects the method to return False and set an appropriate error message.
"""
assert cot_instance.AnalizarXml("<invalid>") is False
assert "no element found" in cot_instance.Excepcion


@pytest.mark.dontusefix
def test_main_function(monkeypatch):
"""
Test the main function of the COT module.
Mocks necessary dependencies and checks if
the function runs without errors.
"""
monkeypatch.setattr(
"sys.argv", ["cot.py", "test_file.txt", "test_user", "test_password"]
)
monkeypatch.setattr(
"pyafipws.cot.COT.PresentarRemito",
lambda self, filename, testing="": True
)
from pyafipws.cot import main

main()


@pytest.mark.dontusefix
def test_cot_initialization(monkeypatch):
"""
Test the initialization and basic functionality of the COT class.
Mocks WebClient and file operations,
then checks various attributes and methods.
"""

def mock_webclient(*args, **kwargs):
return lambda *a, **k: "<dummy_response></dummy_response>"

monkeypatch.setattr("pyafipws.cot.WebClient", mock_webclient)
monkeypatch.setattr("builtins.open", lambda *args: None)
monkeypatch.setattr("os.path.exists", lambda x: True)

cot = COT()
cot.Usuario = "test_user"
cot.Password = "test_password"

cot.Conectar()
assert cot.client is not None

result = cot.PresentarRemito("test_file.txt")
assert result is True
assert cot.XmlResponse == "<dummy_response></dummy_response>"

assert cot.LeerErrorValidacion() is False
assert cot.LeerValidacionRemito() is False
assert cot.AnalizarXml("<test></test>") is True
assert cot.ObtenerTagXml("test") is None

assert cot.InstallDir == INSTALL_DIR
expected_version = (
f"{__version__} {'Homologación' if HOMO else ''}".strip()
)
assert cot.Version.strip() == expected_version
assert set(cot._public_methods_) == {
"Conectar",
"PresentarRemito",
"LeerErrorValidacion",
"LeerValidacionRemito",
"AnalizarXml",
"ObtenerTagXml",
}
assert cot._reg_progid_ == "COT"
assert cot._reg_clsid_ == "{7518B2CF-23E9-4821-BC55-D15966E15620}"


@pytest.mark.dontusefix
def test_presentar_remito_with_different_responses(cot_instance, monkeypatch):
"""
Test PresentarRemito method with various XML responses.
Checks if the method correctly handles different response structures.
"""
responses = [
"<cot><tipoError>0</tipoError></cot>",
(
"<cot><tipoError>1</tipoError><codigoError>E001</codigoError>"
"<mensajeError>Test Error</mensajeError></cot>"
),
(
"<cot><cuitEmpresa>123456789</cuitEmpresa>"
"<numeroComprobante>12345</numeroComprobante></cot>"
),
(
"<cot><validacionesRemitos><remito><numeroUnico>123</numeroUnico>"
"<procesado>SI</procesado><cot>COT123</cot></remito>"
"</validacionesRemitos></cot>"
),
]

for response in responses:
monkeypatch.setattr(
"pyafipws.cot.WebClient",
lambda *args, **kwargs: lambda *a, **k: response
)
monkeypatch.setattr("builtins.open", lambda *args: None)
monkeypatch.setattr("os.path.exists", lambda x: True)

result = cot_instance.PresentarRemito("test.txt")
assert result is False
cot_instance.AnalizarXml(response)


@pytest.mark.dontusefix
def test_presentar_remito_error_handling(cot_instance, monkeypatch):
"""
Test error handling in PresentarRemito method.
Simulates an exception and checks if it's properly handled.
"""

def raise_exception(*args, **kwargs):
raise Exception("Test exception")

monkeypatch.setattr(
"pyafipws.cot.WebClient", lambda *args, **kwargs: raise_exception
)
monkeypatch.setattr("builtins.open", lambda *args: None)
monkeypatch.setattr("os.path.exists", lambda x: True)

result = cot_instance.PresentarRemito("test.txt")
assert result is False
assert cot_instance.Excepcion != ""


@pytest.mark.dontusefix
def test_obtener_tag_xml(cot_instance):
"""
Test ObtenerTagXml method.
Checks if the method correctly retrieves values from XML tags.
"""
xml = (
"<root><tag1>value1</tag1><tag2><subtag>value2</subtag></tag2></root>"
)
cot_instance.xml = SimpleXMLElement(xml)
assert cot_instance.ObtenerTagXml("tag1") == "value1"
assert cot_instance.ObtenerTagXml("tag2", "subtag") == "value2"
assert cot_instance.ObtenerTagXml("nonexistent") is None


@pytest.mark.dontusefix
def test_analizar_xml_error_handling(cot_instance):
"""
Test error handling in AnalizarXml method.
Checks if the method properly handles invalid XML input.
"""
assert cot_instance.AnalizarXml("") is False
assert "no element found" in cot_instance.Excepcion


@pytest.mark.dontusefix
def test_limpiar(cot_instance):
"""
Test limpiar method.
Verifies if the method correctly resets instance attributes.
"""
cot_instance.XmlResponse = "test"
cot_instance.Excepcion = "test"
cot_instance.TipoError = "test"
cot_instance.limpiar()
assert cot_instance.XmlResponse == ""
assert cot_instance.Excepcion == ""
assert cot_instance.TipoError == ""
Loading
Loading