Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Per Unit Test die Serialisierung/Deserialisierung meiner WCF Contract Klassen testen
Wax
myCSharp.de - Member

Avatar #avatar-2276.jpg


Dabei seit:
Beiträge: 745
Herkunft: Dortmund

Themenstarter:

Per Unit Test die Serialisierung/Deserialisierung meiner WCF Contract Klassen testen

beantworten | zitieren | melden

Hallo zusammen,

ich würde gerne per Unit Test die Serialisierung/Deserialisierung meiner WCF Contract Klassen testen.

Um die De-/Serialisierung zu testen, kommt folgende Hilfefunktion zum Einsatz:


public static T DataContractSerializationRoundTrip<T>(T obj, IEnumerable<Type> knownTypes = null)
        {
            T result = default(T);

            var serializer = new DataContractSerializer(obj.GetType());

            using (MemoryStream memoryStream = new MemoryStream())
            {
                serializer.WriteObject(memoryStream, obj);
                memoryStream.Position = 0;
                result = (T)serializer.ReadObject(memoryStream);
            }

            return result;
        }

Das funktioniert für alle meine Typen ohne Probleme.

Zur Laufzeit wirft mein WCF Service am Client allerdings die Fehlermeldung, dass ein nicht erwarteter Typ gefunden wurde und ich diesen doch bitte zur Liste der "KnownTypes" hinzufügen soll. Wenn ich das mache klappt es natürlich wieder, allerdings würde ich gerne etwas Prophylaxe betreiben und diese Fehler bereits per Unit Tests finden.

Wie kann ich also die tatsächliche Serialisierung "simulieren" für den Unit Test?
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3062
Herkunft: Thüringen

beantworten | zitieren | melden

Ich bin mir nicht sicher, was du in dem Codeschnipsel eigentlich testest. So, wie das aussieht, fühlst du dich genötigt, den DataContractSerializer von Hand zu testen....das ergibt so keinen Sinn, denn du möchtest nicht wissen, ob der Serialisierer serialisieren und deserialisieren kann (Hint: er kann), sondern ob DEINE Klassen, wenn sie serialisiert werden, so aussehen, wie du es erwartest.

Davon abgesehen zu deiner Fehlermeldung.
Wenn zur Entwurfszeit nicht klar ist, welchen konkreten Typ eine Eigenschaft haben wird, dann kannst du dem Serialisierer mit dem KnownType-Attribut einen Hinweis auf die Typen geben, die in Frage kommen:


//folgende Konstellation:
interface IExampleInterface { }
class ExampleImplementation : IExampleInterface { }
class AnotherImplementation : IExampleInterface { }

[DataContract]
[KnownType(typeof(ExampleImplementation))]
[KnownType(typeof(AnotherImplementation))]
class ExampleDto
{
    [DataMember]
    public IExampleInterface Property { get; set; }
}

Dasselbe Prinzip erfolgt bei anderen Konstellationen, wo der konkrete Typ nicht erkennbar ist:
- Vererbung
- object als Propertytyp
- IExtensibleDataObject-Implementierungen

In fast allen Fällen hier, in denen der WCF-Dienst dann einen Fault produzierte, obwohl die Unittests durchgingen, war die Ursache nicht der Test, sondern lückenhafte Abdeckung mit TestCases oder fehlerhafte TestCases. Ich würde also als ersten Schritt einen TestCase konstruieren, der wegen des fehlenden KnownType-Attributes in einer SerializationException resultiert. Wenn du das hast, kannst du deine TestCases anpassen und dann deine DataContracts vervollständigen.

LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
private Nachricht | Beiträge des Benutzers
Wax
myCSharp.de - Member

Avatar #avatar-2276.jpg


Dabei seit:
Beiträge: 745
Herkunft: Dortmund

Themenstarter:

beantworten | zitieren | melden

Zitat
der wegen des fehlenden KnownType-Attributes in einer SerializationException resultiert. Wenn du das hast, kannst du deine TestCases anpassen und dann deine DataContracts vervollständigen

Genau das möchte ich erreichen und ich hatte gehofft das ein serialisieren mit dem DataContractSerializer die Exception werfen würde im Fehlerfall.

Ich stehe gerade auf dem Schlauch wie ich diese Exceptions herauskitzeln könnte.

ps: Der UnitTest dazu sieht so aus:


static Object[] DataContractTypes =
        {
            new Object[] {new ItemContainerDTO()},
            new Object[] {new ItemContainerDTO()},
            new Object[] {new DownloadDocumentDTO()},
            new Object[] {new UploadDocumentDTO()},
            new Object[] {new DocumentItemContainerDTO()},
            new Object[] {new DocumentResponseContainerDTO()},
            new Object[] {new ResponseContainerDTO()},
            new Object[] {new UploadDocumentResponseContainerDTO()}
        };


        [TestCaseSource("DataContractTypes")]
        public void ReflectionTest<T>(T source) where T : class
        {
            // Arrange
            ReflectionEqualityComparer<T> comparer = new ReflectionEqualityComparer<T>();

            // Act
            T deserializedObject = DataContractTestHelper.DataContractSerializationRoundTrip<T>(source);

            // Assert
            Assert.IsTrue(comparer.Equals(source, deserializedObject));
        }
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Wax am .
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3062
Herkunft: Thüringen

beantworten | zitieren | melden

In deinen Testcases sind die Dto leer. Tu doch mal was rein. Am besten etwas, das einen Typ hat, der nicht bekannt gemacht wurde.

LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3062
Herkunft: Thüringen

beantworten | zitieren | melden

Beispiel:


[DataContract]
public class ExampleClass
{
    [DataMember]
    public object Property { get; set; }
}

class InternalUnknownClass
{
    public string Name { get; set; }
}

[TestFixture]
class TestClass
{
    IEnumerable<TestCaseData> TestCases
    {
         get 
         { 
              var obj = new ExampleClass { Property = new InternalUnknownClass() };
              yield return new TestCaseData(obj).SetName("UnknownType").Throws(typeof(SerializationException));
        }
    }

    [Test, TestCaseSource("TestCases")]
    public void TestKnownTypes(object dto)
    {
         var serializer = new DataContractSerializer(dto.GetType());
         using(var stream = new MemoryStream())
            serializer.WriteObject(stream, dto);
    }
}

Im Editor geschrieben, nach Bedarf um kleine Tippfehler erleichtern und anpassen ;).

LaTino
EDIT: das Dto und die unbekannte Klasse (muss nicht intern sein) sollten natürlich nicht im Test deklariert sein...dann klappt's auch mit dem Nachbarn.
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von LaTino am .
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
private Nachricht | Beiträge des Benutzers
Wax
myCSharp.de - Member

Avatar #avatar-2276.jpg


Dabei seit:
Beiträge: 745
Herkunft: Dortmund

Themenstarter:

beantworten | zitieren | melden

Ich hatte die ganze Zeit einen falschen Typen verwendet. Jetzt bekomme ich mit meinem Code das gewünschte Verhalten, sprich es werden die Exceptions geworfen, falls ein Typ unbekannt ist.

Danke LaTino.
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3062
Herkunft: Thüringen

beantworten | zitieren | melden

Das sind meistens die Fälle, die einem dann bei Diskussionen um "WCF kann man nicht testen, live verhält sich das anders als im Test" unter die Nase gerieben werden ;).

Btw, die TestCaseSource würde ich immer als IEnumerable<TestCaseData> deklarieren. Dann kann man, wie in meinem Beispiel, schön mit Namen und Ausnahmen und dem ganzen Gedöns arbeiten.

LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
private Nachricht | Beiträge des Benutzers