누수 추상화 및 깨끗한 아키텍처 템플릿
시스템이 더 복잡해짐에 따라 소프트웨어 개발자는 더 많은 추상화에 의존해야 합니다. 각 추상화는 복잡성을 숨기려고 하므로 개발자가 현대 컴퓨팅의 다양한 변형을 "처리"하는 소프트웨어를 작성할 수 있습니다.
그러나 이 법칙은 신뢰할 수 있는 소프트웨어 개발자가 어쨌든 추상화의 기본 세부 사항을 배워야 한다고 주장합니다.
지난 1년 동안 나는 양식Jason Taylor Clean Architecture Solution Template에 영감을 준 클린 아키텍처의 여러 구현을 보았고 모두 공통 인터페이스IApplicationDbContext를 가지고 있습니다. 이 인터페이스는 사용 중인 기본 데이터 액세스 기술을 숨기는 것을 목표로 하지만 인터페이스를 보면 인터페이스가 Entity Framework Core에 연결되어 있음을 알 수 있습니다. 또한 Jason Taylor는 사용자가 항상 EF Core를 사용하고 있으며 변경되지 않을 것이라고 가정했을 것이라고 추측할 수 있습니다.
유출된 추상화가 실제로 작동하는지 봅시다.
UpdateTodoListCommandHandler
에 대한 단위 테스트를 구현하고 실제 프로젝트라고 가정하고 Handle
메서드 내부에 일부 논리가 있지만 각 시나리오에 대한 통합을 구현하지 않습니다. 다음은 실제 구현입니다.namespace CleanArchitecture.Application.TodoLists.Commands.UpdateTodoList
{
public class UpdateTodoListCommand : IRequest
{
public int Id { get; set; }
public string Title { get; set; }
}
public class UpdateTodoListCommandHandler : IRequestHandler<UpdateTodoListCommand>
{
private readonly IApplicationDbContext _context;
public UpdateTodoListCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<Unit> Handle(UpdateTodoListCommand request, CancellationToken cancellationToken)
{
var entity = await _context.TodoLists.FindAsync(request.Id);
if (entity == null)
{
throw new NotFoundException(nameof(TodoList), request.Id);
}
entity.Title = request.Title;
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;
}
}
}
엔티티가 존재하지 않을 때
NotFoundException
가 발생하는지 확인하고 싶습니다.[Test]
public void Update_TodoList_Throws_Exception_When_Entity_Does_Not_Exist()
{
// Arrange
var list = new List<TodoList>();
var queryable = list.AsQueryable();
var dbSet = new Mock<DbSet<TodoList>>();
dbSet.As<IQueryable<TodoList>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<TodoList>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<TodoList>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<TodoList>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(d => d.FindAsync(It.IsAny<object[]>())).ReturnsAsync((object[] id) => list.SingleOrDefault(t => t.Id == (int)id[0]));
var dbContext = new Mock<IApplicationDbContext>();
dbContext.SetupGet(d => d.TodoLists).Returns(dbSet.Object);
var sut = new UpdateTodoListCommandHandler(dbContext.Object);
var command = new UpdateTodoListCommand { Id = 1, Title = "Test" };
// Act
var exception = Assert.ThrowsAsync<NotFoundException>(() => sut.Handle(command, new CancellationToken()));
// Assert
Assert.NotNull(exception);
}
보시다시피 저는 모의
IApplicationDbContext
를 시도했으며 인터페이스는 기본 구현을 숨기는 데 도움이 되어야 하지만 이러한 테스트를 구현하려면 모의DbSet
방법을 알아야 합니다. ApplicationDbContext
인터페이스 대신 IApplicationDbContext
클래스를 사용하면 결과가 동일하고 ApplicationDbContext
클래스를 모의하는 데 동일한 양의 코드가 필요합니다.대신 저장소 패턴을 사용하고 기본 기술을 숨기고 쉽게 조롱할 수 있습니다.
IApplicationDbContext
를 ITodoListRepository
로 바꾸자.public interface ITodoListRepository
{
Task<TodoList> GetByIdAsync(int id);
Task UpdateAsync(TodoList todoList);
}
그리고 핸들러:
public class UpdateTodoListCommandHandler : IRequestHandler<UpdateTodoListCommand>
{
private readonly ITodoListRepository _repository;
public UpdateTodoListCommandHandler(ITodoListRepository repository)
{
_repository = repository;
}
public async Task<Unit> Handle(UpdateTodoListCommand request, CancellationToken cancellationToken)
{
var entity = await _repository.GetByIdAsync(request.Id);
if (entity == null)
{
throw new NotFoundException(nameof(TodoList), request.Id);
}
entity.Title = request.Title;
await _repository.UpdateAsync(entity);
return Unit.Value;
}
}
이제 테스트 방법을 리팩토링할 수 있습니다.
[Test]
public void Test1()
{
// Arrange
var list = new List<TodoList>();
var repository = new Mock<ITodoListRepository>();
repository.Setup(r => r.GetByIdAsync(It.IsAny<int>())).ReturnsAsync((int id) => list.SingleOrDefault(t => t.Id == id));
var command = new UpdateTodoListCommand { Title = "Test", Id = 1 };
var sut = new UpdateTodoListCommandHandler(repository.Object);
// Act
var exception = Assert.ThrowsAsync<NotFoundException>(async () => await sut.Handle(command, new CancellationToken()));
// Act
Assert.NotNull(exception);
Assert.AreEqual(typeof(NotFoundException), exception.GetType());
}
Reference
이 문제에 관하여(누수 추상화 및 깨끗한 아키텍처 템플릿), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/moesmp/leaky-abstraction-and-clean-architecture-template-7nf텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)