No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso de Unit Testing en Go

Curso de Unit Testing en Go

Maria Camila Lenis

Maria Camila Lenis

Manejo de errores y panic en Go

7/15
Recursos

Aportes 8

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Les dejo mi test completo de parser en mi Github.

Lo he utilizado un poco distinto a la clase, básicamente utilizo assert en lugar de require, los ejemplos de error utilizo unos JSON específicos para cada caso y luego he creado la función readSample para simplificar bastante más el código, además de reducir el código duplicado.

go 1.19

Método para leer archivos y desmantelarlo.

func readFileAndUnmarshal[T any](data T, pathFile string) (T, error) {
	body, err := ioutil.ReadFile(pathFile)
	if err != nil {
		return data, err
	}

	err = json.Unmarshal([]byte(body), &data)
	if err != nil {
		return data, err
	}

	return data, nil
}

Dejo mi solucion modificando mi aporte de la clase anterior

Mi archivo parser_test.go

package util

import (
	"catching-pokemons/models"
	"encoding/json"
	"io/ioutil"
	"testing"

	"github.com/stretchr/testify/assert"
)

func loadJsonToMap(pathFile string, data interface{}) error {
	body, err := ioutil.ReadFile(pathFile)
	if err != nil {
		return err
	}

	err = json.Unmarshal([]byte(body), &data)
	if err != nil {
		return err
	}

	return nil
}

func TestParsePokemon(t *testing.T) {
	var apiPokemon map[string]models.PokeApiPokemonResponse
	err := loadJsonToMap("samples/pokeapi_response.json", &apiPokemon)
	assert.NoError(t, err, "Error loading pokeapi_response file")

	var pokemon map[string]models.Pokemon
	err = loadJsonToMap("samples/api_response.json", &pokemon)
	assert.NoError(t, err, "Error loading api_response file")

	type args struct {
		apiPokemon models.PokeApiPokemonResponse
	}
	tests := []struct {
		name    string
		args    args
		want    models.Pokemon
		wantErr error
	}{
		{
			name:    "Success pikachu",
			args:    args{apiPokemon: apiPokemon["pikachu"]},
			want:    pokemon["pikachu"],
			wantErr: nil,
		},
		{
			name:    "Pokemon type not found",
			args:    args{apiPokemon: apiPokemon["pikachuWithNotType"]},
			want:    models.Pokemon{},
			wantErr: ErrNotFoundPokemonType,
		},
		{
			name:    "Pokemon reftype's type is empty",
			args:    args{apiPokemon: apiPokemon["pikachuWithRefTypeEmpty"]},
			want:    models.Pokemon{},
			wantErr: ErrNotFoundPokemonTypeName,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ParsePokemon(tt.args.apiPokemon)

			if err == ErrNotFoundPokemonType || err == ErrNotFoundPokemonTypeName {
				assert.NotNil(t, err, "ParsePokemon() error = %v, wantErr %v", err, tt.wantErr)
				assert.EqualError(t, err, tt.wantErr.Error(), "ParsePokemon() error = %v, wantErr %v", err, tt.wantErr)
			} else {
				assert.NoError(t, err, "ParsePokemon() error = %v, wantErr %v", err, tt.wantErr)
				assert.Equal(t, tt.want, got, "ParsePokemon() = %v, want %v", got, tt.want)
			}
		})
	}
}

mi archivo api_response.json el cual no sufre cambios

{
    "pikachu": {
        "Id": 25,
        "Name": "pikachu",
        "Type": "electric",
        "Abilities": {
            "Attack": 55,
            "Defense": 40,
            "Hp": 35,
            "Speed": 90
        }
    },
    "bulbasaur": {
        "Id": 1,
        "Name": "bulbasaur",
        "Type": "grass",
        "Abilities": {
            "Attack": 49,
            "Defense": 49,
            "Hp": 45,
            "Speed": 45
        }
    },
    "charmander": {
        "Id": 4,
        "Name": "charmander",
        "Type": "fire",
        "Abilities": {
            "Attack": 52,
            "Defense": 43,
            "Hp": 39,
            "Speed": 65
        }
    },
    "squirtle": {
        "Id": 7,
        "Name": "squirtle",
        "Type": "water",
        "Abilities": {
            "Attack": 48,
            "Defense": 65,
            "Hp": 44,
            "Speed": 43
        }
    }
}

Mi archivo pokeapi_response.json

{
    "pikachu" : {
        "id": 25,
        "name": "pikachu",
        "types": [
            {
                "slot": 1,
                "type": {
                    "name": "electric"
                }
            }
        ],
        "stats": [
            {
                "base_stat": 35,
                "stat": {
                    "name": "hp"
                }
            },
            {
                "base_stat": 55,
                "stat": {
                    "name": "attack"
                }
            },
            {
                "base_stat": 40,
                "stat": {
                    "name": "defense"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-attack"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-defense"
                }
            },
            {
                "base_stat": 90,
                "stat": {
                    "name": "speed"
                }
            }
        ]
    },
    "pikachuWithNotType" : {
        "id": 25,
        "name": "pikachu",
        "types": [],
        "stats": [
            {
                "base_stat": 35,
                "stat": {
                    "name": "hp"
                }
            },
            {
                "base_stat": 55,
                "stat": {
                    "name": "attack"
                }
            },
            {
                "base_stat": 40,
                "stat": {
                    "name": "defense"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-attack"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-defense"
                }
            },
            {
                "base_stat": 90,
                "stat": {
                    "name": "speed"
                }
            }
        ]
    },
    "pikachuWithRefTypeEmpty" : {
        "id": 25,
        "name": "pikachu",
        "types": [
            {
                "slot": 1,
                "type": {
                    "name": ""
                }
            }
        ],
        "stats": [
            {
                "base_stat": 35,
                "stat": {
                    "name": "hp"
                }
            },
            {
                "base_stat": 55,
                "stat": {
                    "name": "attack"
                }
            },
            {
                "base_stat": 40,
                "stat": {
                    "name": "defense"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-attack"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-defense"
                }
            },
            {
                "base_stat": 90,
                "stat": {
                    "name": "speed"
                }
            }
        ]
    },
    "bulbasaur": {
        "id": 1,
        "name": "bulbasaur",
        "types": [
            {
                "slot": 1,
                "type": {
                    "name": "grass"
                }
            },
            {
                "slot": 2,
                "type": {
                    "name": "poison"
                }
            }
        ],
        "stats": [
            {
                "base_stat": 45,
                "stat": {
                    "name": "hp"
                }
            },
            {
                "base_stat": 49,
                "stat": {
                    "name": "attack"
                }
            },
            {
                "base_stat": 49,
                "stat": {
                    "name": "defense"
                }
            },
            {
                "base_stat": 65,
                "stat": {
                    "name": "special-attack"
                }
            },
            {
                "base_stat": 65,
                "stat": {
                    "name": "special-defense"
                }
            },
            {
                "base_stat": 45,
                "stat": {
                    "name": "speed"
                }
            }
        ]
    },
    "charmander": {
        "id": 4,
        "name": "charmander",
        "types": [
            {
                "slot": 1,
                "type": {
                    "name": "fire"
                }
            }
        ],
        "stats": [
            {
                "base_stat": 39,
                "stat": {
                    "name": "hp"
                }
            },
            {
                "base_stat": 52,
                "stat": {
                    "name": "attack"
                }
            },
            {
                "base_stat": 43,
                "stat": {
                    "name": "defense"
                }
            },
            {
                "base_stat": 60,
                "stat": {
                    "name": "special-attack"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-defense"
                }
            },
            {
                "base_stat": 65,
                "stat": {
                    "name": "speed"
                }
            }
        ]
    },
    "squirtle": {
        "id": 7,
        "name": "squirtle",
        "types": [
            {
                "slot": 1,
                "type": {
                    "name": "water"
                }
            }
        ],
        "stats": [
            {
                "base_stat": 44,
                "stat": {
                    "name": "hp"
                }
            },
            {
                "base_stat": 48,
                "stat": {
                    "name": "attack"
                }
            },
            {
                "base_stat": 65,
                "stat": {
                    "name": "defense"
                }
            },
            {
                "base_stat": 50,
                "stat": {
                    "name": "special-attack"
                }
            },
            {
                "base_stat": 64,
                "stat": {
                    "name": "special-defense"
                }
            },
            {
                "base_stat": 43,
                "stat": {
                    "name": "speed"
                }
            }
        ]
    }
}

Mi Implementacion para ambos casos

func TestParsePokemonToDTO_WhenTypeNotFound(t *testing.T) {
	apiPokemon := entities.PokemonApiResponse{}
	err := json.Unmarshal(pokemonFromApi, &apiPokemon)
	assert.NoError(t, err)

	apiPokemon.PokemonType = []entities.PokemonType{}
	parsePokemon, err := ParsePokemonToDTO(apiPokemon)
	assert.NotNil(t, err)
	assert.EqualError(t, fmt.Errorf("pokemon type not found"), err.Error())
	assert.Equal(t, parsePokemon, dto.Pokemon{})
}

func TestParsePokemonToDTO_WhenTypeNameNotFound(t *testing.T) {
	apiPokemon := entities.PokemonApiResponse{}
	err := json.Unmarshal(pokemonFromApi, &apiPokemon)
	assert.NoError(t, err)

	apiPokemon.PokemonType[0].RefType = entities.BaseName{}
	parsePokemon, err := ParsePokemonToDTO(apiPokemon)
	assert.NotNil(t, err)
	assert.EqualError(t, fmt.Errorf("pokemon type name not found"), err.Error())
	assert.Equal(t, parsePokemon, dto.Pokemon{})
}

Mi implementación de test para el ErrNotFoundPokemonTypeName (Bastaba con cambiar el primer índice del array PokemonType, pero decidí cambiarlos todos con un for):

func TestParserTypeNameNotFound(t *testing.T) {
  c := require.New(t)
  
  // Ger response sended by pokeapi 
  // (simulate the get request)
  body, err := ioutil.ReadFile("samples/pokeapi_response.json")
  c.NoError(err)
    
  // Transform into struct
  var response models.PokeApiPokemonResponse
  err = json.Unmarshal([]byte(body), &response)
  c.NoError(err)

  // *** Remove all pokemon types names ***
  // This will cause the test to fail
  for index := range response.PokemonType {
    response.PokemonType[index].RefType.Name = ""
  }
 
  // Parse struct WITH OUR METHOD 
  // and test the expected error
  _, err = ParsePokemon(response)
  c.NotNil(err)
  c.EqualError(ErrNotFoundPokemonTypeName, err.Error())
}

Adjunto un test para el Type Name Error

func TestParserPokemonTypeNameNotFound(t *testing.T) {
	c := require.New(t)

	body, err := ioutil.ReadFile("samples/pokeapi_response.json")
	c.NoError(err)
	response := models.PokeApiPokemonResponse{}
	err = json.Unmarshal([]byte(body), &response)
	c.NoError(err)

	response.PokemonType[0].RefType.Name = ""
	_, err = ParsePokemon(response)
	c.NotNil(err)
	c.EqualError(ErrNotFoundPokemonTypeName, err.Error())
}

Mi ejemplo de los tests en el archivo parser

func TestParsePokemon(t *testing.T) {
	t.Run("Success", func(t *testing.T) {
		body, err := ioutil.ReadFile("samples/pokeapi_response.json")
		assert.NoError(t, err)

		var response models.PokeApiPokemonResponse

		err = json.Unmarshal(body, &response)
		assert.NoError(t, err)

		result, err := ParsePokemon(response)
		assert.NoError(t, err)

		apiResponse, err := ioutil.ReadFile("samples/api_response.json")
		assert.NoError(t, err)

		var expected models.Pokemon

		err = json.Unmarshal(apiResponse, &expected)
		assert.NoError(t, err)

		assert.Equal(t, expected, result)
	})

	t.Run("TypeNotFound", func(t *testing.T) {
		body, err := ioutil.ReadFile("samples/pokeapi_response.json")
		assert.NoError(t, err)

		var response models.PokeApiPokemonResponse

		err = json.Unmarshal(body, &response)
		assert.NoError(t, err)

		response.PokemonType = []models.PokemonType{}

		_, err = ParsePokemon(response)
		assert.Error(t, err)
		assert.Errorf(t, err, ErrNotFoundPokemonType.Error())
	})

	t.Run("TypeNameNotFound", func(t *testing.T) {
		body, err := ioutil.ReadFile("samples/pokeapi_response.json")
		assert.NoError(t, err)

		var response models.PokeApiPokemonResponse

		err = json.Unmarshal(body, &response)
		assert.NoError(t, err)

		response.PokemonType[0].RefType.Name = ""

		_, err = ParsePokemon(response)
		assert.Error(t, err)
		assert.Errorf(t, err, ErrNotFoundPokemonTypeName.Error())
	})
}