Wie kann ich eine DataServiceQuery für Unit-Test-Zwecke verspotten?Verspotten eines DataServiceQuery <TElement>
Lange Einzelheiten folgen: eine ASP.NET MVC-Anwendung Stellen Sie sich vor, in dem die Steuerung spricht mit einem ADO.NET Dataservice, das die Speicherung unserer Modelle kapselt (zum Beispiel aus Gründen werden wir eine Liste der Kunden liest). Mit einem Verweis auf den Dienst, erhalten wir eine generierte Klasse von Dataservicecontext erben:
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 */
}
}
Der Regler könnte:
namespace Sample.Controllers
{
public class CustomerController : Controller
{
private IMyDataContext context;
public CustomerController(IMyDataContext context)
{
this.context=context;
}
public ActionResult Index() { return View(context.Customers); }
}
}
Wie Sie sehen können, habe ich einen Konstruktor, der so eine IMyDataContext Instanz akzeptiert dass wir ein Modell in unserer Unit-Test verwenden:
[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 und MyDataContext müssen die gleiche Schnittstelle IMyDataContext implementieren:
namespace Sample.Services
{
public interface IMyDataContext
{
DataServiceQuery<Customer> Customers { get; }
/* and more */
}
}
Wenn wir jedoch die MockContext Klasse versuchen und implementieren, führen wir in Probleme aufgrund der Art von Dataservicequery (was klar zu sein, wir sind einfach in der IMyDataContext Schnittstelle verwenden, da, dass der Typ Daten ist fanden wir in der automatisch generierten MyDataContext-Klasse, mit der wir begonnen haben). Wenn wir zu schreiben versuchen:
public class MockContext : IMyDataContext
{
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers { get { /* ??? */ } }
}
In den Kunden Getter möchten wir eine Instanz Dataservicequery instanziiert, füllen Sie es mit den Kunden in CustomersToReturn, und es zurückgeben. Die Probleme, denen ich begegne:
1 ~ DataServiceQuery hat keinen öffentlichen Konstruktor; Um einen zu instanziieren, sollten Sie CreateQuery für einen DataServiceContext aufrufen. siehe MSDN
2 ~ Wenn ich die MockContext von Dataservicecontext erben machen als auch, und rufen Sie Create eine Dataservicequery zu bekommen zu verwenden, den Service und die Abfrage haben einen gültigen URI und gebunden werden, wenn ich versuche, iterieren oder auf die Objekte in der Abfrage zugreifen, wird es gegen diesen URI versuchen und ausführen. Mit anderen Worten, wenn ich die MockContext als solche zu ändern:
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;
}
}
}
}
Dann wird in dem Unit-Test, erhalten wir einen Fehler auf der Linie als LINE A markiert, weil http://www.contoso.com nicht unseren Service hostet. Derselbe Fehler wird auch dann ausgelöst, wenn LINE A versucht, die Anzahl der Elemente in Modellen abzurufen. Vielen Dank im Voraus.
Dror, danke für die Idee, aber für die Zeit, indem wir sind keine Mockframework. Wir wären daran interessiert zu sehen, ob es eine Lösung gibt, die nicht auf einem beruht. Immer noch, danke – FOR
Haben Sie einen bestimmten Grund, kein spöttisches Framework zu verwenden? –
Im Allgemeinen keine spezifischen Gründe. Wir stellen es vielleicht vor, aber es ist unwahrscheinlich, dass wir es für diese spezielle Aufgabe über Nacht tun werden. Nehmen wir an, wir möchten jetzt eine Lösung finden, ohne ein spöttisches Framework hinzuzufügen. – FOR