2009-02-12 12 views
21

Ich schreibe eine Befehlszeilenschnittstelle zu meinem Projekt. Der Benutzer gibt "create project foo" ein und findet den Controller, der für "project" verantwortlich ist, und ruft dann die Create-Methode auf, wobei "foo" als erstes Argument übergeben wird.Kann ich Moq Attribute zur Scheinklasse hinzufügen?

Es stützt sich stark auf Attribute und Reflexion: Der Controller sieht ungefähr so ​​aus:

[ControllerFor("project")] 
class ProjectController 
{ 
    [ControllerAction("create")] 
    public object Create(string projectName) { /* ... */ } 
} 

ich Moq in den Unit-Tests für den Parser, so etwas wie diese verwenden möchten:

Mock<IProjectsController> controller = new Mock<IProjectsController>(); 
controller.Expect(f => f.Create("foo")); 

parser.Register(controller.Object); 
parser.Execute("create project foo"); 

controller.VerifyAll(); 

Das Hinzufügen der Attribute zur Schnittstelle scheint nicht zu funktionieren - sie werden nicht von abgeleiteten Klassen geerbt.

Kann ich Moq zum Hinzufügen von Attributen zu der Klasse, die verspottet wird, bekommen?

Antwort

31

Update: Ich habe gerade festgestellt, dass Sie tatsächlich Attribute zu einem vorhandenen Typ TypeDescriptor.AddAttributes unter Verwendung hinzufügen können, die für eine Instanz ausgeführt werden kann oder AA Typ:

Mock<IRepository> repositoryMock = new Mock<IRepository>(); 

CustomAttribute attribute = new CustomAttribute(); 

// option #1: to the instance 
TypeDescriptor.AddAttributes(repositoryMock.Object, attribute); 

// option #2: to the generated type 
TypeDescriptor.AddAttributes(repositoryMock.Object.GetType(), attributes); 

Wenn Sie es brauchen, AddAttribute gibt einen TypeDescriptorProvider zurück, der an TypeDescriptor.RemoveProvider übergeben werden kann, um die Attribute anschließend zu entfernen.

Beachten Sie, dass Attribute.GetCustomAttributes keine Attribute finden, die zur Laufzeit auf diese Weise hinzugefügt werden. Verwenden Sie stattdessen TypeDescriptor.GetAttributes.

Original-Antwort

Ich glaube nicht Moq (oder andere spöttische Rahmen für diese Angelegenheit) unterstützt benutzerdefinierte Attribute. Ich weiß, dass Castle Proxy (das Framework, das üblicherweise verwendet wird, um die Klasse zu erstellen) unterstützt es unterstützt, aber es gäbe keine Möglichkeit, über Moq darauf zuzugreifen.

Ihre beste Wette besteht darin, Ihre Methode zum Laden von Attributen in eine Schnittstelle zu abstrahieren (die den Typ und den Attributtyp akzeptiert) und sich dann darüber lustig zu machen.

Edit: Zum Beispiel:

public interface IAttributeStrategy 
{ 
    Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit); 
    Attribute[] GetAttributes(Type owner, bool inherit); 
} 

public class DefaultAttributeStrategy : IAttributeStrategy 
{ 
    public Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit) 
    { 
     return owner.GetCustomAttributes(attributeType, inherit); 
    } 

    public Attribute[] GetAttributes(Type owner, bool inherit) 
    { 
     return owner.GetCustomAttributes(inherit); 
    } 
} 

Die Klasse, die die Attribute verwendet eine Instanz von IAttributeStrategy muss (entweder durch einen IoC Behälter oder mit ihm wahlweise in den Konstruktor übergeben). Normalerweise wird es eine DefaultAttributeStrategy sein, aber Sie können jetzt IAttributeStrategy vortäuschen, um die Ausgabe zu überschreiben.

Es klingt vielleicht kompliziert, aber das Hinzufügen einer Abstraktionsschicht ist viel einfacher, als zu versuchen, Attribute nachzuahmen.

+0

Können Sie den Schnittstellenansatz erweitern? Ich denke nicht, dass es zu dem passt, was ich tue, aber ich würde es gerne sehen, um sicher zu gehen. –

+0

Siehe meine aktualisierte Antwort auf TypeDescriptor.AddAttributes –

+0

(lassen Sie mich wissen, wenn meine aktualisierte Antwort Ihr Problem löst und ich die alten Teile der Antwort entfernen werde) –