2009-05-19 1 views
6

Ich habe eine Aktion-Methode wie dies in meinem ControllerWie moq ich ein ISingleResult? Sollte ich? oder gibt es eine bessere Methode?

public ActionResult Index() 
{ 
    using (NorthwindDataContext db = new NorthwindDatacontext()) 
    { 
     var results = db.GetRecordSets(arg1, ....).ToList(); 
     // use results as list 
    } 

    return View(); 
} 

und ich wollte es machen Tests starten (ja, nachdem sie gebaut wurde, nicht vor ... aber der Code geschrieben wurde, bevor ich begann zu verwenden TDD so ...)

und ich herausgefunden, dass eine Eigenschaft wie dieser an die Steuerung

Zugabe
public delegate NorthwindDatacontext ContextBuilderDelegate(); 

public ContextBuilderDelegate ContextBuilder { get; set; } 

ich im Konstruktor so etwas wie diese könnte hinzufügen ...

ContextBuilder =() => new NorthwindDatacontext(); 

dann konnte ich die ActionMethod testen Sie die ContextBuilder Eigenschaft mit einem Mock von NorthwindDatacontext Einstellung

var controller    = new MyController(); 
var mockDataContext   = new Mock<NorthwindDatacontext>(); 
controller.ContextBuilder =() => mockDataContext.Object; 

Aber ... ich keine Möglichkeit gefunden, dies zu verwenden, da alle Methoden der NorthwindDatacontext als Rückgabetyp verwenden ISingleResult und ich kippe finde den Weg, um ein Objekt mit dieser Schnittstelle zu erstellen. Ich habe versucht, diese

var theResult     = new List<GetRecordSetsResult>(); 
// fill the data structure here with the provided result... 

mockDataContext.Setup(c => c. GetRecordSets()).Returns(theResult as 
              ISingleResult<GetRecordSetsResult>); 

aber es funktioniert nicht, weil theResult null ist, wenn zu ISingleResult umgewandelt.

Gibt es eine Möglichkeit, ein ISingleResult-Objekt zu erstellen, um auf diese Weise zu testen, oder mache ich den falschen Weg, um die Dinge hier zu tun?

Vielen Dank im Voraus

+0

Danke, Ihre Frage und die erste Antwort hat mir wirklich geholfen, mich zu lösen Problem. – Odd

Antwort

3

ToList() ist eine Erweiterung Methode für IEnumerable, die leicht zu verspotten, weil es ein Mitglied Verfahren nur hat - GetEnumerator().

Dennoch könnten Sie Probleme spöttische NorthwindDataContext Klasse haben, wenn seine Methoden nicht virtuell sind ...

Auch immer, das ist, wie ich ein ähnliches Problem in meinem Sandbox gelöst, hoffen, es hilft:

public class MyType 
{ 
    public virtual ISingleResult<int> ReturnSomeResult() { throw new NotImplementedException(); } 
} 

[TestMethod] 
public void TestMethod1() 
{ 
    var mockMyType = new Mock<MyType>(); 
    var mockSingleResult = new Mock<ISingleResult<int>>(); 
    IEnumerable<int> someEnumerable = new int[] {1,2,3,4,5}; 
    mockSingleResult.Setup(result => result.GetEnumerator()).Returns(someEnumerable.GetEnumerator()); 
    mockMyType.Setup(myType => myType.ReturnSomeResult()).Returns(mockSingleResult.Object); 

    Assert.AreEqual(15, mockMyType.Object.ReturnSomeResult().ToList().Sum()); 
} 
+0

Große Antwort ... das würde ich auch machen. – womp

+1

Sorry, ich fühle mich hier wie ein Idiot, weil ich nicht sehen kann, wie ich mein Problem lösen kann. Ich sehe es als einen guten Ansatz, aber es löst nicht, was ich brauche. Ich habe Rob Conerys MVC Storefront-Videos angeschaut und kann sehen, dass das Repository-Muster das ist, was ich brauche, aber das ist nicht einfach mit LinqToSql-Datenkontexten zu implementieren, wie ich sehen kann. –

+0

Große Antwort, löste mein Problem. – Odd

5

Ich habe eine Klasse erstellt, die ISingleResult implementiert und einfach eine Liste darin eingefügt. Ich bin ziemlich neu in dieser Art der Codierung, also während dies für mich funktionierte, verwenden Sie auf eigene Gefahr (und wenn Sie Löcher sehen einen Kommentar).

class SingleResult<T>:ISingleResult<T> 
{ 
    readonly List<T> _list = new List<T>(); 

    public void Add(T item) 
    { 
     _list.Add(item); 
    } 

    #region Interface Items 

    public IEnumerator<T> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public object ReturnValue { get { return _list; } } 

    public void Dispose() { } 

    #endregion 
} 

Dies kann dann verwendet werden, um einen Teil eines Mocks zurückzugeben. Dies ist, wie ich es mit Rhino Mocks verwendet:

[TestMethod] 
public void TestSomething() 
{ 
    //Arrange 
    // Make a data context and DAL 
    var _ctx = MockRepository.GenerateMock<IDataClassesDataContext>(); 
    var someDALClass = new SomeDALClass(_ctx); 

    User testUser = UserObjectHelper.TestUser(); 
    SingleResult<User> userList = new SingleResult<User> { testUser }; 

    // Indicate that we expect a call the to sproc GetUserByUserID 
    _ctx.Expect(x => x.GetUserByUserID(testUser.UserID)).Return(userList); 

    //Act 
    someDALClass.UpdateUser(testUser); 

    //Assert 
    Assert.IsTrue(SomeTestCondition()); 
} 
+0

Sehr gut, +1. Ich verwende diese Klasse mit ein paar Änderungen: 1. '_list' ist ein' IEnumerable 'anstelle von' List '. 2. Ich übergebe eine gebrauchsfertige Sammlung im Klassenkonstruktor anstelle einer 'Add'-Methode. – Konamiman

Verwandte Themen