-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
985ce56
commit 7ef88ae
Showing
2 changed files
with
207 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
Para entender os conceitos utilizados neste código em relação a testes unitários precisamos focar em alguns princípios chave e práticas que facilitam a testabilidade do código. Vou abordar os conceitos principais utilizados neste código e como eles se relacionam com testes unitários. | ||
|
||
### Conceitos Utilizados no Código | ||
|
||
1. **Injeção de Dependência (Dependency Injection)**: | ||
- **Definição**: É um padrão de design que permite a injeção de dependências (objetos que uma classe precisa para funcionar) em uma classe através do seu construtor ou métodos. | ||
- **No código**: O repositório `IEmployeeRepository` é injetado no construtor da classe `EmployeeService`. | ||
|
||
```csharp | ||
public EmployeeService(IEmployeeRepository repository) | ||
{ | ||
_repository = repository; | ||
} | ||
``` | ||
|
||
- **Para testes unitários**: A injeção de dependência facilita a substituição de dependências reais por mocks ou stubs durante os testes, permitindo isolar a unidade de código que está sendo testada. | ||
|
||
2. **Interface**: | ||
- **Definição**: Interfaces são contratos que definem quais métodos e propriedades uma classe deve implementar, sem fornecer a implementação real. | ||
- **No código**: `IEmployeeRepository` é uma interface que define o método `Add`. | ||
|
||
```csharp | ||
public interface IEmployeeRepository | ||
{ | ||
void Add(Employee employee); | ||
} | ||
``` | ||
|
||
- **Para testes unitários**: O uso de interfaces permite a criação de mocks. Você pode criar uma implementação falsa (`mock`) de `IEmployeeRepository` para testar o comportamento da `EmployeeService` sem interagir com a camada de dados real. | ||
|
||
3. **Mocking**: | ||
- **Definição**: É o processo de criação de objetos falsos que imitam o comportamento de objetos reais. Mocks são usados para testar a interação entre unidades de código. | ||
- **Para testes unitários**: Em testes, você pode usar bibliotecas de mocking (como Moq em C#) para criar um mock de `IEmployeeRepository` e verificar se os métodos corretos foram chamados. | ||
|
||
### Exemplo de Teste Unitário com Moq | ||
|
||
Aqui está um exemplo de como você poderia escrever um teste unitário para o método `Add` da `EmployeeService` usando a biblioteca Moq: | ||
|
||
```csharp | ||
using Moq; | ||
using Xunit; | ||
using HrManager.Application.Models.InputModels; | ||
using HrManager.Application.Models.ViewModels; | ||
using HrManager.Application.Services; | ||
using HrManager.Core.Repositories; | ||
|
||
public class EmployeeServiceTests | ||
{ | ||
[Fact] | ||
public void Add_Should_Call_Repository_Add_And_Return_ViewModel() | ||
{ | ||
// Arrange | ||
var mockRepository = new Mock<IEmployeeRepository>(); | ||
var service = new EmployeeService(mockRepository.Object); | ||
var inputModel = new AddEmployeeInputModel | ||
{ | ||
// Inicialize o modelo de entrada com dados de teste | ||
}; | ||
var expectedEmployee = inputModel.ToEntity(); | ||
|
||
// Act | ||
var result = service.Add(inputModel); | ||
|
||
// Assert | ||
mockRepository.Verify(r => r.Add(It.Is<Employee>(e => e == expectedEmployee)), Times.Once); | ||
Assert.NotNull(result); | ||
Assert.IsType<AddEmployeeViewModel>(result); | ||
Assert.Equal(expectedEmployee.Name, result.Name); // Exemplo de verificação de propriedade | ||
} | ||
} | ||
``` | ||
|
||
### Explicação do Teste Unitário | ||
|
||
1. **Arrange**: Configuramos o cenário do teste. | ||
- Criamos um mock de `IEmployeeRepository` usando Moq. | ||
- Criamos uma instância do `EmployeeService` passando o mock do repositório. | ||
- Inicializamos um `AddEmployeeInputModel` com dados de teste. | ||
- Convertemos o modelo de entrada em uma entidade esperada. | ||
|
||
2. **Act**: Executamos o método `Add` do `EmployeeService`. | ||
|
||
3. **Assert**: Verificamos se o método `Add` do repositório foi chamado uma vez com a entidade esperada. | ||
- Usamos `mockRepository.Verify` para verificar a interação com o mock. | ||
- Checamos se o resultado não é nulo e se é do tipo correto. | ||
- Verificamos propriedades específicas no resultado para garantir que os dados foram processados corretamente. | ||
|
||
### Conclusão | ||
|
||
O código utiliza injeção de dependência e interfaces para promover a separação de preocupações e facilitar o teste. Isso permite a criação de testes unitários eficazes, onde dependências externas podem ser mockadas para isolar a unidade de código que está sendo testada. O uso de bibliotecas de mocking como Moq facilita a verificação de interações e comportamento do código em testes. | ||
|
||
### Tecnologias | ||
- XUnit | ||
- Moq (Mock) | ||
- Auto fixture | ||
- Shouldly | ||
|
||
|
||
Esse código é um exemplo de testes unitários usando a biblioteca xUnit.net, Moq para criação de mocks, AutoFixture para geração de dados aleatórios e Shouldly para assertivas de teste mais expressivas. Vamos analisar cada parte do código: | ||
|
||
### Estrutura Geral | ||
|
||
```csharp | ||
using AutoFixture; | ||
using HrManager.Application.Models.InputModels; | ||
using HrManager.Application.Services; | ||
using HrManager.Core.Entities; | ||
using HrManager.Core.Exceptions; | ||
using HrManager.Core.Repositories; | ||
using Moq; | ||
using Shouldly; | ||
using System; | ||
using Xunit; | ||
|
||
namespace HrManager.UnitTests.Application.Services.EmployeeServiceTests | ||
{ | ||
public class EmployeeServiceAddTests | ||
{ | ||
[Fact] | ||
public void ValidEmployee_AddIsCalled_ReturnValidEmployeeViewModel() | ||
{ | ||
// Arrange | ||
var addEmploymentInputModel = new Fixture().Create<AddEmployeeInputModel>(); | ||
|
||
var employeeRepositoryMock = new Mock<IEmployeeRepository>(); | ||
|
||
var employeeService = new EmployeeService(employeeRepositoryMock.Object); | ||
|
||
// Act | ||
var result = employeeService.Add(addEmploymentInputModel); | ||
|
||
// Assert | ||
Assert.Equal(addEmploymentInputModel.Role, result.Role); | ||
Assert.Equal(addEmploymentInputModel.FullName, result.FullName); | ||
Assert.Equal(addEmploymentInputModel.Document, result.Document); | ||
Assert.Equal(addEmploymentInputModel.BirthDate, result.BirthDate); | ||
Assert.Equal(addEmploymentInputModel.RoleLevel, result.RoleLevel); | ||
Assert.Equal(addEmploymentInputModel.Role, result.Role); | ||
|
||
result.FullName.ShouldBe(addEmploymentInputModel.FullName); | ||
result.Document.ShouldBe(addEmploymentInputModel.Document); | ||
result.BirthDate.ShouldBe(addEmploymentInputModel.BirthDate); | ||
result.RoleLevel.ShouldBe(addEmploymentInputModel.RoleLevel); | ||
result.Role.ShouldBe(addEmploymentInputModel.Role); | ||
|
||
employeeRepositoryMock.Verify(er => er.Add(It.IsAny<Employee>()), Times.Once); | ||
} | ||
|
||
[Fact] | ||
public void InvalidBirthDateForEmployee_AddIsCalled_ThrowAnInvalidBirthDateException() | ||
{ | ||
// Arrange | ||
var addEmploymentInputModel = new Fixture().Create<AddEmployeeInputModel>(); | ||
addEmploymentInputModel.BirthDate = DateTime.Today.AddDays(1); | ||
|
||
var employeeRepositoryMock = new Mock<IEmployeeRepository>(); | ||
var employeeService = new EmployeeService(employeeRepositoryMock.Object); | ||
|
||
// Act + Assert | ||
var exception = Assert.Throws<BirthDateCannotBeInTheFutureException>(() => | ||
employeeService.Add(addEmploymentInputModel)); | ||
|
||
Assert.Equal("Birth date cannot be in the future.", exception.Message); | ||
|
||
Should.Throw<BirthDateCannotBeInTheFutureException>(() => | ||
employeeService.Add(addEmploymentInputModel)) | ||
.Message.ShouldBe("Birth date cannot be in the future."); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Explicação | ||
|
||
#### Usings | ||
|
||
- **Usings Iniciais**: Importações de namespaces necessários para o teste, incluindo `AutoFixture` para criação de dados aleatórios, definições de modelos (`AddEmployeeInputModel`), serviços (`EmployeeService`), entidades (`Employee`), exceções (`BirthDateCannotBeInTheFutureException`) e repositórios (`IEmployeeRepository`). | ||
|
||
#### Namespace e Classe de Teste | ||
|
||
- **Namespace `HrManager.UnitTests.Application.Services.EmployeeServiceTests`**: A estrutura do namespace sugere que esses testes estão no contexto de testes para a classe `EmployeeService` no projeto `Application.Services` dentro do projeto `HrManager`. | ||
- **Classe `EmployeeServiceAddTests`**: Classe de testes para testar o método `Add` da classe `EmployeeService`. | ||
|
||
#### Métodos de Teste | ||
|
||
1. **`ValidEmployee_AddIsCalled_ReturnValidEmployeeViewModel`**: | ||
- **Arrange**: Preparação para o teste. Utiliza o `AutoFixture` para criar um `AddEmployeeInputModel` com dados aleatórios. | ||
- Cria um mock de `IEmployeeRepository` e o injeta no `EmployeeService`. | ||
- Modifica a data de nascimento (`BirthDate`) para garantir que não seja no futuro. | ||
- **Act**: Chama o método `Add` do `EmployeeService` com o modelo de entrada criado. | ||
- **Assert**: Verifica se o método `Add` do repositório foi chamado uma vez com qualquer instância de `Employee`. Compara as propriedades do resultado (`result`) com as propriedades do modelo de entrada (`addEmploymentInputModel`) usando assertivas do xUnit (`Assert.Equal`) e Shouldly (`result.FullName.ShouldBe`, etc.). | ||
|
||
2. **`InvalidBirthDateForEmployee_AddIsCalled_ThrowAnInvalidBirthDateException`**: | ||
- **Arrange**: Prepara um `AddEmployeeInputModel` com uma data de nascimento (`BirthDate`) no futuro. | ||
- Cria um mock de `IEmployeeRepository` e o injeta no `EmployeeService`. | ||
- **Act + Assert**: Verifica se chamar o método `Add` do `EmployeeService` com um modelo de entrada inválido resulta em uma exceção do tipo `BirthDateCannotBeInTheFutureException`. Usa assertivas do xUnit (`Assert.Throws`) e Shouldly (`Should.Throw`) para validar a exceção e sua mensagem. | ||
|
||
### Considerações Finais | ||
|
||
- **Mocking (`Mock<IEmployeeRepository>`)**: Usado para simular o comportamento do repositório de empregados sem realmente acessar o banco de dados. | ||
- **AutoFixture**: Utilizado para criar dados aleatórios, facilitando a preparação de cenários de teste. | ||
- **Assertivas**: | ||
- **xUnit (`Assert.Equal`, `Assert.Throws`)**: Assertivas padrão do xUnit para verificar resultados. | ||
- **Shouldly (`ShouldBe`, `Should.Throw`)**: Lib adicional para assertivas mais expressivas e legíveis. | ||
|
||
Este código exemplifica uma abordagem típica de teste unitário em C#, onde cada método de teste é focado em validar um cenário específico e verificar o comportamento esperado da classe `EmployeeService` ao adicionar empregados. |