문제

단위 테스트 목적으로 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;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top