Autor Beitrag
casio1234
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 21.05.13 12:50 
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:
ausblenden 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()
        {
            //var test = new ScreenManagerTest();
           // test.Run();

            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:
ausblenden C#-Quelltext
1:
2:
3:
 public MainScreen(GraphicsDevice device, string name) : base(device, name)
        {
        }

welcher den Konstruktor von Screen aufruft:
ausblenden 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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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?

Für diesen Beitrag haben gedankt: casio1234
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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.


Zuletzt bearbeitet von Th69 am Di 21.05.13 13:43, insgesamt 1-mal bearbeitet
casio1234 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 21.05.13 13:43 
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: 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.