2017-09-04 3 views
2

.NET Core 2.0 및 .NET Core MongoDB 드라이버를 사용하고 있습니다.IMongoQueryable을 사용한 단위 테스트

그래서 같은 저장소를 만든 :이 그들이 EF를 사용 할 것 흡사 LINQ을 할 수 있도록 사용하는 누구에 유연성을 제공하기 위해 이런 짓을했는지

public interface IRepository<T> 
{ 
    IMongoQueryable<T> Get() 
} 

. 문제는 단위 테스트에 관한 것이고 작업 전후의 상태를 확인할 수 있도록 메모리 내장 데이터베이스를 만들려고합니다.

일부 물건은 내가 시도 :

public class InMemoryRepository : IRepository<ConcreteType> 
{ 
    private HashSet<ConcreteType> _data = new HashSet<ConcreteType>(); 

    public IMongoQueryable<ConcreteType> Get() 
    { 
     return (IMongoQueryable<ConcreteType>)_data.AsQueryable(); 
    } 
} 

사건이 IMongoQueryable의 인터페이스로 작동하지 않을 수 있습니다 :

public interface IMongoQueryable<T> : IMongoQueryable, IQueryable, IEnumerable, IQueryable<T>, IEnumerable<T>, IAsyncCursorSource<T> 

또 다른 이동 :

public class InMemoryRepository : IRepository<ConcreteType> 
{ 
    private HashSet<ConcreteType> _data = new HashSet<ConcreteType>(); 

    public InMemoryRepository() 
    { 
     _mongoQueryableMock = new Mock<IMongoQueryable<ConcreteType>>(); 
     _mongoQueryableMock.Setup(m => m.AsQueryable()).Returns(_data.AsQueryable); 
    } 

    public IMongoQueryable<ConcreteType> Get() 
    { 
     return _mongoQueryableMock.Object; 
    } 
} 

이되지 않습니다 IMongoQueryable.AsQueryable()은 확장 방법이므로 모의/설정을 할 수 없습니다.

+1

구현의 동작을 올바르게 모방 할 수 없기 때문에 IQueryable 인터페이스를 조롱하는 것은 항상 어렵고 위험합니다. 결과적으로 실제 MongoDb 인스턴스에 대해서는 작동하지 않을 수도 있습니다. 저장소의 역할은 응용 프로그램의 비즈니스 논리에서 데이터 액세스 기술을 추상화하는 것입니다. 저장소가 MongoDb 특정 인터페이스를 비즈니스 계층에 노출하면 누수 된 추상화가 발생합니다. 비즈니스 논리를 특정 데이터 액세스 기술에 묶을 위험이 있습니다. –

답변

1

IQueryable 호를 처리 할 수 ​​있도록 모의을 구성하십시오. 내가 저장소의 디자인이 새는이며, 외부 종속성에 직접적으로 커플 코드 생각하는 방식 중 그와


public class InMemoryRepository : IRepository<ConcreteType> { 
    private HashSet<ConcreteType> _data = new HashSet<ConcreteType>(); 
    private Mock<IMongoQueryable<ConcreteType>> _mongoQueryableMock; 

    public ReviseMeasureRepository() {  
     var queryableList = _data.AsQueryable(); 

     _mongoQueryableMock = new Mock<IMongoQueryable<ConcreteType>>(); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.Provider).Returns(queryableList.Provider); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.Expression).Returns(queryableList.Expression); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.ElementType).Returns(queryableList.ElementType); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());  
    } 

    public IMongoQueryable<ConcreteType> Get() { 
     return _mongoQueryableMock.Object; 
    } 

    //... 
} 

. 저장소 추상화 설계 검토를 고려하십시오.

+0

이것이이 질문의 범위를 벗어나지는 않았지만 그것에 대한 아이디어가 있습니까? '.Take()'와'.Offset()'을 사용하고 싶다면 그것들을위한 특별한 메소드를 작성해야 할 것입니다. 저장소를 결합하지 않고 다른 CRUD 방법과 함께 사용할 수 있도록 만들려고했으나 컬렉션 반환을위한 행복한 매체를 찾을 수 없었습니다. 분명히 데이터베이스의 모든 것을 반환하고 메모리에서 원하는 것을 필터링하도록하고 싶지는 않습니다. –

+1

@KevinLee, 그건 완전히 새로운 질문입니다. 추상화를위한 추상화의 문제이기도합니다. 원하는 행동을 추상화합니다. 따라서 공개하고자하는 API를 타겟으로하십시오. IQueryable 노출은 새어 나옵니다. '.Take()'와'.Offset()'은 원하는 동작을 구현하여 구현해야하는 구현 관련 사항입니다. – Nkosi