Come posso simulare un DataServiceQuery per lo scopo di test dell'unità?Mocking di un DataServiceQuery <TElement>
lunghe articolate come segue: Immaginate un'applicazione ASP.NET MVC, in cui i colloqui controller a una DataService ADO.NET che incapsula l'archiviazione dei nostri modelli (ad esempio l'amor saremo leggendo un elenco di clienti). Con un riferimento al servizio, otteniamo una classe generata eredita da 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 */
}
}
Il controller potrebbe essere:
namespace Sample.Controllers
{
public class CustomerController : Controller
{
private IMyDataContext context;
public CustomerController(IMyDataContext context)
{
this.context=context;
}
public ActionResult Index() { return View(context.Customers); }
}
}
Come potete vedere, ho usato un costruttore che accetta un'istanza IMyDataContext così che possiamo usare un modello nel nostro test di unità:
[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 e MyDataContext hanno bisogno di implementare la stessa interfaccia di IMyDataContext:
namespace Sample.Services
{
public interface IMyDataContext
{
DataServiceQuery<Customer> Customers { get; }
/* and more */
}
}
Tuttavia, quando cerchiamo di implementare la classe MockContext, ci imbattiamo in problemi a causa della natura di DataServiceQuery (che, per essere chiari, stiamo usando nell'interfaccia IMyDataContext semplicemente perché questo è il tipo di dati che abbiamo trovato nella classe MyDataContext generata automaticamente che abbiamo iniziato con). Se proviamo a scrivere:
public class MockContext : IMyDataContext
{
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers { get { /* ??? */ } }
}
Negli Clienti getter vorremmo istanziare un'istanza DataServiceQuery, popolarlo con i clienti in CustomersToReturn, e restituirlo. I problemi che ho incontrato:
1 ~ DataServiceQuery non ha un costruttore pubblico; per istanziare uno si dovrebbe chiamare CreateQuery su un DataServiceContext; vedi MSDN
2 ~ Se faccio il MockContext ereditare da DataServiceContext pure, e chiamare createQuery per ottenere un DataServiceQuery da utilizzare, il servizio e la richiesta devono essere legato ad un URI valido e, quando provo a iterare o accedere agli oggetti nella query, proverà ed eseguirà contro quell'URI. In altre parole, se cambio la MockContext in quanto tale:
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;
}
}
}
}
Poi, nel test di unità, otteniamo un errore sulla linea contrassegnata come LINE A, perché http://www.contoso.com non ospita il nostro servizio. Lo stesso errore viene attivato anche se LINEA tenta di ottenere il numero di elementi nei modelli. Grazie in anticipo.
Dror, grazie per l'idea, ma per il momento non stiamo utilizzando qualsiasi quadro di scherno. Saremmo interessati a vedere se esiste una soluzione che non si basa su uno. Ancora, grazie – FOR
Hai una ragione specifica per non usare una struttura di simulazione? –
In generale, nessun motivo specifico. Potremmo introdurlo, ma è improbabile che lo faremo durante la notte per questo specifico compito. Quindi, diciamo che per ora vorremmo trovare una soluzione senza aggiungere una struttura di derisione. – FOR