Frage

ich irrte, wenn es möglich ist, ein Spiel-Objekt, um zu verspotten meine DrawableGameComponent Komponente zu testen?

Ich weiß, dass spöttischen Frameworks eine Schnittstelle, um zu funktionieren müssen, aber ich brauche die tatsächliche Game Objekt.

edit: Hier ist ein Link jeweilige Diskussion über XNA Community-Foren rel="nofollow . Jede Hilfe?

War es hilfreich?

Lösung

Es gibt einige gute Beiträge in diesem Forum zum Thema Unit-Tests. Hier ist meine persönliche Annäherung an Unit-Tests in XNA:

  • Ignoriere den Draw () Methode
  • Isolieren komplizierte Verhalten in Ihren eigenen Klassenmethoden
  • Testen Sie die kniffligen Sachen, den Rest erledigt nicht schwitzen

Hier ist ein Beispiel für einen Test, um zu bestätigen, dass meine Methode Update Entities den richtigen Abstand zwischen Update () ruft bewegt. (Ich verwende NUnit .) Getrimmt ich ein paar Zeilen mit verschiedenen Bewegungsvektoren, aber Sie bekommen die Idee: Sie kein Spiel benötigen, sollten Sie Ihre Tests fahren

.
[TestFixture]
public class EntityTest {
    [Test]
    public void testMovement() {
        float speed = 1.0f; // units per second
        float updateDuration = 1.0f; // seconds
        Vector2 moveVector = new Vector2(0f, 1f);
        Vector2 originalPosition = new Vector2(8f, 12f);

        Entity entity = new Entity("testGuy");
        entity.NextStep = moveVector;
        entity.Position = originalPosition;
        entity.Speed = speed;

        /*** Look ma, no Game! ***/
        entity.Update(updateDuration);

        Vector2 moveVectorDirection = moveVector;
        moveVectorDirection.Normalize();
        Vector2 expected = originalPosition +
            (speed * updateDuration * moveVectorDirection);

        float epsilon = 0.0001f; // using == on floats: bad idea
        Assert.Less(Math.Abs(expected.X - entity.Position.X), epsilon);
        Assert.Less(Math.Abs(expected.Y - entity.Position.Y), epsilon);
    }
}

Edit: Einige andere Hinweise aus den Kommentaren:

Meine Entity Klasse : Ich entschied mich für all mein Spiel in einer zentralen Entity-Klasse-Objekte bis wickeln, dass so etwas wie folgt aussieht:

public class Entity {
    public Vector2 Position { get; set; }
    public Drawable Drawable { get; set; }

    public void Update(double seconds) {
        // Entity Update logic...
        if (Drawable != null) {
            Drawable.Update(seconds);
        }
    }

    public void LoadContent(/* I forget the args */) {
        // Entity LoadContent logic...
        if (Drawable != null) {
            Drawable.LoadContent(seconds);
        }
    }
}

Das gibt mir eine Menge Flexibilität Subklassen von Entity (AIEntity, NonInteractiveEntity ...), die wahrscheinlich überschreiben Update () zu machen. Es lässt mich auch Drawable Unterklasse frei, ohne die Hölle von n ^ 2 Subklassen wie AnimatedSpriteAIEntity, ParticleEffectNonInteractiveEntity und AnimatedSpriteNoninteractiveEntity. Stattdessen kann ich dies tun:

Entity torch = new NonInteractiveEntity();
torch.Drawable = new AnimatedSpriteDrawable("Animations\litTorch");
SomeGameScreen.AddEntity(torch);

// let's say you can load an enemy AI script like this
Entity enemy = new AIEntity("AIScritps\hostile");
enemy.Drawable = new AnimatedSpriteDrawable("Animations\ogre");
SomeGameScreen.AddEntity(enemy);

Meine Drawable Klasse : Ich habe eine abstrakte Klasse, von der alle meine gezeichneten Objekte abgeleitet werden. Ich entschied mich für eine abstrakte Klasse, weil einige das Verhalten geteilt werden. Es wäre durchaus akzeptabel sein, dies zu definieren als Schnittstelle statt, wenn das nicht wahr Ihren Codes.

public abstract class Drawable {
    // my game is 2d, so I use a Point to draw...
    public Point Coordinates { get; set; }
    // But I usually store my game state in a Vector2,
    // so I need a convenient way to convert. If this
    // were an interface, I'd have to write this code everywhere
    public void SetPosition(Vector2 value) {
        Coordinates = new Point((int)value.X, (int)value.Y);
    }

    // This is overridden by subclasses like AnimatedSprite and ParticleEffect
    public abstract void Draw(SpriteBatch spriteBatch, Rectangle visibleArea);
}

Die Unterklassen definieren ihre eigene Draw Logik. In Ihrem Tank Beispiel könnten Sie ein paar Dinge tun:

  • Fügen Sie eine neue Einheit für jede Kugel
  • Erstellen Sie eine TankEntity Klasse, die eine Liste definiert, und überschreibt Draw () über die Kugeln
  • (die eine Draw-Methode ihrer eigenen Definition) iterieren
  • Erstellen Sie eine ListDrawable

Hier ist ein Beispiel-Implementierung von ListDrawable, ohne auf die Frage, wie die Liste verwalten sich selbst.

public class ListDrawable : Drawable {
    private List<Drawable> Children;
    // ...
    public override void Draw(SpriteBatch spriteBatch, Rectangle visibleArea) {
        if (Children == null) {
            return;
        }

        foreach (Drawable child in children) {
            child.Draw(spriteBatch, visibleArea);
        }
    }
}

Andere Tipps

Frameworks wie MOQ und Rhino Mocks nicht speziell eine Schnittstelle benötigen. Sie können spotten alle nicht versiegelt und / oder abstrakte Klasse als auch. Spiel ist eine abstrakte Klasse, so dass Sie keine Probleme spöttischen es haben sollte: -)

Das einzige, was mit mindestens diesen beiden Frameworks zu beachten ist, dass alle Erwartungen auf Methoden oder Eigenschaften zu setzen, sie virtuell oder abstrakt sein muss. Der Grund dafür ist, dass die verspottet Instanz es muss in der Lage außer Kraft zu setzen erzeugt. Die Typemock erwähnt von IAmCodeMonkey Ich glaube, hat einen Weg, um dieses, aber ich glaube nicht, Typemock frei ist, während die beiden, die ich erwähnt sind.

Als beiseite, Sie können auch ein Projekt von mir überprüfen, die bei der Schaffung von Unit-Tests für XNA-Spiele ohne die Notwendigkeit Mocks machen helfen könnten: http://scurvytest.codeplex.com/

Sie müssen es nicht verspotten. Warum nicht ein gefälschtes Spielobjekt machen?

Vererben von Spiel und überschreiben Sie die Methoden, die Sie beabsichtigen, in Ihren Tests verwenden Dosen-Werte oder die Verknüpfung Berechnungen aus welchen Methoden zurückzukehren / Eigenschaften, die Sie benötigen. Dann die gefälschte Pass auf Ihre Tests.

Vor dem spöttischen Frameworks, rollten die Menschen ihre eigenen Mocks / Stubs / Fakes - vielleicht ist es nicht so schnell und einfach, aber man kann immer noch

.

Sie können ein Tool namens TypeMock, dass ich glaube, dass Sie nicht benötigen eine Schnittstelle haben. Ihre andere und häufiger gefolgt Methode ist eine neue Klasse zu erstellen, die von Spiel erbt und implementiert auch eine Schnittstelle, die Sie erstellen, dass passen das Spiel-Objekt. Sie können dann Code gegen diese Schnittstelle und übergeben Sie in Ihrem ‚custom‘ Game-Objekt.

public class MyGameObject : Game, IGame
{
    //you can leave this empty since you are inheriting from Game.    
}

public IGame
{
    public GameComponentCollection Components { get; set; }
    public ContentManager Content { get; set; }
    //etc...
}

Es ist ein bisschen langweilig, aber es lässt Sie mockability erreichen.

Ich werde Schweinchen auf Ihre Post zurück, wenn Sie da Mine scheint weniger aktiv zu sein, und Sie setzen Ihre rep bereits auf der Linie;)

Als ich durch deine Beiträge lesen (beide hier & XNAForum) Ich denke, es ist sowohl der Rahmen, der mehr ansprechbar sein könnte und mein (unser) Design, das nicht einwandfrei ist.

könnte der Rahmen erweitert werden einfacher gestaltet haben werden. Ich habe eine harte Zeit Shawn 's glauben Hauptargument eines auf Schnittstellen getroffen Perf . So sichern Sie mich sein Kollege sagt der perf Hit sein könnte easely ausgewichen.
Sie beachten, dass der Rahmen bereits eine IUpdatable und IDrawable Schnittstelle. Warum nicht den ganzen Weg?

Auf der anderen Seite denke ich auch, dass in der Tat meines (und Ihre) Design nicht fehlerlos ist. Wo ich auf dem Spielobjekt nicht hängen, ich auf dem Graphics hängen stark widersprechen. Ich werde sehen, wie ich das umgehen kann. Es ist gonna make Code komplizierter, aber ich denke, ich kann in der Tat diese Abhängigkeiten brechen.

Für einen Ausgangspunkt auf so etwas wie dieses, würde ich die XNA WinForms Probe . Unter Verwendung dieser Probe als Modell scheint es, dass eine Möglichkeit, Komponenten in einem WinForm zu visualisieren ist eine Steuerung für sie im gleichen Stil wie die SpinningTriangleControl aus der Probe zu erstellen. Dies zeigt, wie XNA Code ohne Spiel Instanz zu machen. Wirklich das Spiel ist nicht wichtig, sein, was es für Sie tut, was zählt. Also, was Sie tun würden, ist ein Bibliotheksprojekt erstellen, die die Last hat / Zeichnen Logik der Komponente in einer Klasse und in Ihren anderen Projekten eine Control-Klasse und eine Komponentenklasse erstellen, die Wrapper für die Bibliothek Code in ihren jeweiligen Umgebungen sind. Auf diese Weise wird der Code Ihre Tests nicht dupliziert und Sie müssen sich keine Gedanken über das Schreiben von Code Sorge, dass immer lebensfähig sein werden in zwei unterschiedlichen Szenarien.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top