Entwickler-Ecke
C# - Die Sprache - Null-Pointer Exception Unit Test
casio1234 - Di 21.05.13 12:50
Titel: Null-Pointer Exception Unit Test
Hey,
mein erster Beitrag hier. :) Bisher hatte ich nur mit C++ und Java gearbeitet und muss jetzt was in C# machen. Zur Sache:
Ich bin dran ein Spiel zu programmieren, hierzu verwende ich XNA. Implementiert wird gerade ein ScreenManager der Objekte der Klasse Screen verwaltet und dann entsprechend auf den Bildschirm malt. Das funktioniert an sich ganz gut. Um Fehler auszuschliessen hab ich Unit-Tests geschrieben und sie gehen nicht. Ich komme dem Fehler nicht so ganz auf die Spur.
Es gibt insgesamt drei Klassen: ScreenManager welche static ist und Objekte der Klasse Screen verwaltet, welche abstract ist. Sowie dann noch die von Screen geerbte Klasse MainScreen. Getestet wird im Moment nur die ScreenManager-Klasse mit ScreenManagerTest welche von Game erbt.
Um zu testen ob zum ScreenManager ein Objekt von MainScreen hinzugefuegt werden kann folgender Testcase:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| [TestMethod] public void AddScreenTest() { const string s1 = "MainScreen1"; const string s2 = "MainScreen2"; const string s3 = "MainScreen3";
var graphicsDevice = new GraphicsDeviceManager(this).GraphicsDevice; Screen screen1 = new MainScreen(graphicsDevice, s1); Screen screen2 = new MainScreen(graphicsDevice, s2); Screen screen3 = new MainScreen(graphicsDevice, s3); ScreenManager.AddScreen(screen1); ScreenManager.AddScreen(screen2); ScreenManager.AddScreen(screen3); Assert.AreEqual(2, ScreenManager.GetScreenNumber()); Assert.IsNotNull(ScreenManager.GetScreen(0)); Assert.IsNotNull(ScreenManager.GetScreen(1)); Assert.AreEqual(screen1, ScreenManager.GetScreen(0)); Assert.AreEqual(screen2, ScreenManager.GetScreen(1)); } |
Das Problem ist jetzt dass es in Zeile 12 beim anlegen des Objektes zu einer Null-Pointer-Exception kommt. Diese kommt aus dem Konstruktor von MainScreen:
C#-Quelltext
1: 2: 3:
| public MainScreen(GraphicsDevice device, string name) : base(device, name) { } |
welcher den Konstruktor von Screen aufruft:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| protected Screen(GraphicsDevice device, string name) { if (device == null) { throw new ArgumentNullException("device"); } Name = name; mDevice = device; } |
Zeile 7 mit Name = name macht hierbei ein Problem. Per Debugger habe ich rausgefunden, dass "name" einen richtigen Wert beinhaltet, "Name" hingegen nicht. Es wird also nicht richtig kopiert...
Die Property Name:
C#-Quelltext
1:
| public string Name { get; private set; } |
Ich habe nicht so recht eine Ahnung warum es zu einem Fehler kommt. :( Dachte erst das liegt am private des set, rein logisch ueberlegt ist das natuerlich Unsinn. Trotzdem mal auf public gesetzt und den gleichen Effekt gehabt. Wenn ich mit dem Debugger das Objekt genauer anschaue, stell ich fest dass "name" zwei mal vorkommt, obwohl es doch nur einmal da sein sollte?! C# verwirrt mich hier etwas, waere super wenn jemand von euch eine Antwort kennt.
Danke schon mal fuer die Hilfe!
Th69 - Di 21.05.13 13:04
Hallo casio1234,
beim bisher gezeigten Source-Code sehe ich auch keine Fehler.
Aber es sollte auch keine NullReferenceEcxeption (nicht Null-Pointer-Exception ;-)) bei der Zuweisung Name = name auftreten.
Hast du evtl. zwei verschiedene Eigenschaften Name in MainScreen als auch der Basisklasse Screen angelegt?
casio1234 - Di 21.05.13 13:17
Nochmal nachgeschaut, es ist eine ArgumentNullException. Nein, zwei mal Name kommt nicht vor. Es gibt nur das public string Name { get; private set; } in Screen.
Ralf Jansen - Di 21.05.13 13:36
Und es nicht zufällig deine eigene? Bei einer selbst geworfenen Exception hält der Debugger häufiger auf der Zeile danach. Zumindest sieht es im Debugger so aus es ist aber der throw vorher gemeint. Wenn du dir dann den Inhalt von Name anschaust steht da natürlich noch nichts drin weil die Zeile noch nicht ausgeführt wurde.
Liefert dein GraphicsDeviceManager eventuell null als GraphicsDevice?
Th69 - Di 21.05.13 13:41
Ja dann ist die Sache ja eindeutig ;-)
Du solltest dann also auch einen Unit-Test für diesen Fehlerfall schreiben.
casio1234 - Di 21.05.13 13:43
Ralf Jansen hat folgendes geschrieben : |
Und es nicht zufällig deine eigene? Bei einer selbst geworfenen Exception hält der Debugger häufiger auf der Zeile danach. Zumindest sieht es im Debugger so aus es ist aber der throw vorher gemeint. Wenn du dir dann den Inhalt von Name anschaust steht da natürlich noch nichts drin weil die Zeile noch nicht ausgeführt wurde.
Liefert dein GraphicsDeviceManager eventuell null als GraphicsDevice? |
Du hast recht! Danke. Irgendeine spontane Idee wie ich das GraphicDevice zur mitarbeit ueberreden kann?
Th69 - Di 21.05.13 13:55
Hello again,
casio1234 hat folgendes geschrieben: |
Getestet wird im Moment nur die ScreenManager-Klasse mit ScreenManagerTest welche von Game erbt. |
Das
this in
C#-Quelltext
1:
| new GraphicsDeviceManager(this).GraphicsDevice; |
entspricht ja deiner ScreenManagerTest-Klasse.
Du solltest aber eine eigene von Game abgeleitete Klasse in deinem Projekt haben, die du dann hier in der Testklasse benutzen solltest.
Oder aber noch besser eine Mock-Klasse benutzen, welche die XNA-Schnittstelle
IGraphicsDeviceManager kapselt.
Leider bietet
GraphicsDevice keine eigene Schnittstelle an, mit der du die Unit-Tests ohne explizite Instantiierung durchführen lassen könntest.
Ralf Jansen - Di 21.05.13 13:56
Nicht wirklich. Ohne Ahnung von XNA kann ich dir nur Raten zu überlegen was im Test anders ist als in einer richtigen XNA Applikation.
Was ist denn das übergebene this für ein Ding das du da an den GraphicsDeviceManager übergibst? Ist das Ding richtig initialisiert (was immer das heißt) so das es ein GraphicssDevice hat?
@TH69 Wenn der Test keine Ableitung von Game ist sollte doch schon der Compiler meckern?
Th69 - Di 21.05.13 14:06
Hallo Ralf,
ich meinte es so, daß es mir komisch vorkommt, daß man die Testklasse von Game erben läßt.
Wahrscheinlich hat der OT dies nur gemacht, um den Compilerfehler zu beseitigen (aber deswegen wird eine Testklasse noch lange nicht zu einer XNA-Game-Klasse!).
Ergänzung: Bei einem Unit-Test wird ja nur die einzelne Unit-Methode ausgeführt und nicht die gesamte Applikation (d.h. hier also das XNA-Framework) und daher gibt es dann auch kein initialisiertes GraphicsDevice.
casio1234 - Di 21.05.13 14:14
Eigentlich interessiert mich das GraphicsDevice nicht, es geht in dem Testcase nur darum ob ScreenManager richtig mit den Objekten die es verwaltet umgeht. Von Game habe ich die Test-Klasse nur erben lassen damit ich auf das GraphicsDevice zugriff habe wie es auch in der Main-Class (da funktioniert alles 1A und diese erbt auch von Game) gemacht wurde.
Eigentlich koennte ich auch einen eigenen Konstruktor in MainScreen ohne Paramter rein machen, da es eben nur um die Objekt-Verwaltung und nicht um den Inhalt der Objekte geht. Allerdings straeube ich mich dagegen an dem Quelltext rumzupfuschen nur damit der Testcase geht.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!