Um A
und Mock-Schnittstelle zu testen InterfaceB
Sie A
so zu schreiben, dass es für eine Instanz von InterfaceB
nicht verantwortlich ist. Stattdessen erhält es über seinen Konstruktor eine Instanz von InterfaceB
.
Sie werden diese Muster über sehen und immer wieder:
public A()
{
private readonly InterfaceB _b;
public A(InterfaceB b)
{
_b = b;
}
public string functionA()
{
if(String.IsNullOrEmpty(_b.GetId())) return String.Empty;
else if(String.IsNullOrEmpty(_b.GetKey())) return String.Empty;
else return _b.GetToken();
}
}
Dies wird Dependency Injection genannt. Es bedeutet, dass die Abhängigkeit einer Klasse in sie "injiziert" wird und nicht die Klasse, die sie erzeugt. Wenn wir uns so in den Konstruktor einfügen, nennen wir es auch "Konstruktorinjektion", aber gewöhnlich ist es nur "Abhängigkeitsinjektion". Und es ist einer der Gründe, warum wir es verwenden, wenn wir Schnittstellen nachahmen können.
Ein paar wichtigen Details:
- Da
InterfaceB
an den Konstruktor übergeben werden, nichts in A
immer „weiß“, was die tatsächliche Umsetzung ist. Es könnte alles sein. Daher ist A
niemals an eine konkrete Implementierung gebunden. (Deshalb können Sie "spotten" InterfaceB
.)
- Das Feld
_b
ist readonly
. Das ist nicht unbedingt notwendig, aber es bedeutet, dass _b
nur vom Konstruktor gesetzt und nie wieder geändert werden kann. Das betont, dass A
nur dieses empfängt und verwendet. Diese Klasse steuert nie, was ist. Was auch immer erzeugtA
bestimmt, was dieser Wert ist.
Nun, wenn Sie ein Gerät zu testen gerade schreiben Sie verspott Implementierungen von InterfaceB
erstellen können, die genau tun, was Sie wollen, wie
public class MockedInterfaceB : InterfaceB
{
private string _id;
private string _key;
private string _token;
public MockedInterfaceB(string id, string key, string token);
{
_id = id;
_key = key;
_token = token;
}
public string GetId() {return _id};
public string GetKey() {return _key};
public string GetToken() {return _token};
}
Und dann in Ihrem Unit-Test können Sie die Implementierung verwenden:
var testA = new A(new MockedInterfaceB("myid","mykey","mytoken"));
Sie können auch Tools wie Moq verwenden, um diese Mocks einfacher zu erstellen.
Wenn Sie von der Abhängigkeitsinjektion hören, befindet es sich oft im Kontext eines Abhängigkeitsinjektionscontainers wie Castle Windsor, Autofac oder Unity. Dies sind nützliche Werkzeuge, die Sie bei der Arbeit mit Abhängigkeitsinjektionen unterstützen. Sie sind es wert, darüber zu lernen.Bei der Abhängigkeitsinjektion geht es jedoch nur darum, wie Sie die Klassen schreiben, wie im obigen Beispiel, wo wir die Abhängigkeit (InterfaceB
) in die Klasse A
"injizieren".
Sie einen Konstruktor auf 'A' benötigen, die ein' InterfaceB' als Parameter übernimmt, dann können Sie entweder direkt ein verspottete Objekt 'InterfaceB' zu diesem Kontruktor oder eingestellt für die Injektion, wenn Sie DI verwenden, auch wenn nur für diesen Test. – starlight54