DataServiceQuery 를 조롱합니다
-
10-07-2019 - |
문제
단위 테스트 목적으로 DataServiceQuery를 어떻게 조롱 할 수 있습니까?
긴 세부 사항은 다음과 같습니다. ASP.NET MVC 응용 프로그램을 상상해보십시오. 컨트롤러가 모델의 저장을 캡슐화하는 ADO.NET DataService와 대화하는 ASP.NET MVC 응용 프로그램을 상상해보십시오 (예 : Sake는 고객 목록을 읽을 것입니다). 서비스를 참조하여 DataServiceContext에서 생성 된 클래스 상속을 얻습니다.
namespace Sample.Services
{
public partial class MyDataContext : global::System.Data.Services.Client.DataServiceContext
{
public MyDataContext(global::System.Uri serviceRoot) : base(serviceRoot) { /* ... */ }
public global::System.Data.Services.Client.DataServiceQuery<Customer> Customers
{
get
{
if((this._Customers==null))
{
this._Customers = base.CreateQuery<Customer>("Customers");
}
return this._Customers;
}
}
/* and many more members */
}
}
컨트롤러는 다음과 같습니다.
namespace Sample.Controllers
{
public class CustomerController : Controller
{
private IMyDataContext context;
public CustomerController(IMyDataContext context)
{
this.context=context;
}
public ActionResult Index() { return View(context.Customers); }
}
}
보시다시피, 나는 단위 테스트에서 모의를 사용할 수 있도록 imydatacontext 인스턴스를 수용하는 생성자를 사용했습니다.
[TestFixture]
public class TestCustomerController
{
[Test]
public void Test_Index()
{
MockContext mockContext = new MockContext();
CustomerController controller = new CustomerController(mockContext);
var customersToReturn = new List<Customer>
{
new Customer{ Id=1, Name="Fred" },
new Customer{ Id=2, Name="Wilma" }
};
mockContext.CustomersToReturn = customersToReturn;
var result = controller.Index() as ViewResult;
var models = result.ViewData.Model;
//Now we have to compare the Customers in models with those in customersToReturn,
//Maybe by loopping over them?
foreach(Customer c in models) //*** LINE A ***
{
//TODO: compare with the Customer in the same position from customersToreturn
}
}
}
MockContext 및 MyDataconText는 동일한 인터페이스 IMYDATACONTEXT를 구현해야합니다.
namespace Sample.Services
{
public interface IMyDataContext
{
DataServiceQuery<Customer> Customers { get; }
/* and more */
}
}
그러나 MockContext 클래스를 시도하고 구현하면 DataServiceQuery의 특성으로 인해 문제가 발생합니다 (명확하게 말하면, 우리는 자동 생성 된 MyDataconText에서 찾은 데이터 유형이기 때문에 ImyDataconText 인터페이스에 사용하고 있습니다. 우리가 시작한 수업). 우리가 쓰려고한다면 :
public class MockContext : IMyDataContext
{
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers { get { /* ??? */ } }
}
고객 Getter에서는 DataServiceQuery 인스턴스를 인스턴스화하고 CustomErsoreturn의 고객과 함께 채우고 반환하고 싶습니다. 내가 겪는 문제 :
1~ DataServiceQuery에는 공개 생성자가 없습니다. 하나를 인스턴스화하려면 DataServiceContext에서 Createquery를 호출해야합니다. 보다 MSDN
2~ MockContext를 DataServiceContext에서도 상속하고 Createquery를 호출하여 DataServiceQuery를 사용할 수 있으면 서비스와 쿼리가 유효한 URI에 연결되어야하며 쿼리의 개체를 반복하거나 액세스하려고하면됩니다. 그 우리에 대해 시도하고 실행하십시오. 다시 말해, MockContext를 변경하면 다음과 같이 변경합니다.
namespace Sample.Tests.Controllers.Mocks
{
public class MockContext : DataServiceContext, IMyDataContext
{
public MockContext() :base(new Uri("http://www.contoso.com")) { }
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers
{
get
{
var query = CreateQuery<Customer>("Customers");
query.Concat(CustomersToReturn.AsEnumerable<Customer>());
return query;
}
}
}
}
그런 다음 단위 테스트에서 라인 A로 표시된 줄에 오류가 발생합니다. http://www.contoso.com 우리의 서비스를 주최하지 않습니다. 라인 A가 모델에서 요소 수를 얻으려고 시도하더라도 동일한 오류가 트리거됩니다. 미리 감사드립니다.
해결책
면책 조항 - 나는 Typemock에서 일합니다
조롱 프레임 워크 사용을 고려해 보셨습니까?
TypEmock Isolator를 사용하여 DataServiceQuery의 가짜 인스턴스를 만들 수 있습니다.
var fake = Isolate.Fake.Instance<DataServiceQuery>();
또한 유사한 가짜 DataServiceContext를 생성하고 상속을 시도하는 대신 동작을 설정할 수 있습니다.
다른 팁
인터페이스를 만들어 이것을 해결했습니다 IDataServiceQuery
두 가지 구현 :
DataServiceQueryWrapper
MockDataServiceQuery
그런 다음 사용합니다 IDataServiceQuery
내가 이전에 사용했을 때마다 a DataServiceQuery
.
public interface IDataServiceQuery<TElement> : IQueryable<TElement>, IEnumerable<TElement>, IQueryable, IEnumerable
{
IDataServiceQuery<TElement> Expand(string path);
IDataServiceQuery<TElement> IncludeTotalCount();
IDataServiceQuery<TElement> AddQueryOption(string name, object value);
}
그만큼 DataServiceQueryWrapper
a DataServiceQuery
생성자에서 모든 기능을 전달한 쿼리로 위임합니다. 마찬가지로 MockDataServiceQuery
가져갑니다 IQueryable
그리고 쿼리에 가능한 모든 것을 위임합니다.
조롱을 위해 IDataServiceQuery
방법, 나는 현재 그냥 돌아옵니다 this
, 원한다면 기능을 조롱하기 위해 무언가를 할 수 있습니다.
예를 들어:
// (in DataServiceQueryWrapper.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return new DataServiceQueryWrapper<TElement>(_query.Expand(path));
}
// (in MockDataServiceQuery.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return this;
}