문제

drawablegamecomponent 구성 요소를 테스트하기 위해 게임 객체를 조롱 할 수 있다면 방황하고 있었습니까?

조롱 프레임 워크는 작동하기 위해서는 인터페이스가 필요하다는 것을 알고 있지만 실제를 조롱해야합니다. 게임 물체.

편집 : 다음은 다음과 같습니다 링크 XNA 커뮤니티 포럼에 대한 각각의 토론. 도움이 있습니까?

도움이 되었습니까?

해결책

해당 포럼에는 단위 테스트 주제에 대한 좋은 게시물이 있습니다. 다음은 XNA의 단위 테스트에 대한 개인적인 접근 방식입니다.

  • Draw () 메소드를 무시하십시오
  • 자신의 계급 방법에서 복잡한 행동을 분리하십시오
  • 까다로운 물건을 테스트하고 나머지는 땀을 흘리지 마십시오

다음은 내 업데이트 메소드가 Entities가 update () 호출 사이의 적절한 거리를 이동하도록 확인하기위한 테스트의 예입니다. (사용 중입니다 NUNIT.) 나는 다른 움직임 벡터로 몇 줄을 다듬었지만 아이디어를 얻습니다. 테스트를 주도하기 위해 게임이 필요하지 않습니다.

[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);
    }
}

편집 : 댓글의 다른 메모 :

내 엔티티 클래스: 나는 모든 게임 객체를 중앙 집중식 엔티티 클래스에서 마무리하기로 결정했습니다.

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);
        }
    }
}

이것은 나에게 update ()를 무시하는 엔티티 (aientity, nonincintactive…)의 서브 클래스를 만들 수있는 많은 유연성을 제공합니다. 또한 N^2 서브 클래스와 같은 지옥없이 서브 클래스를 자유롭게 끌 수 있습니다. AnimatedSpriteAIEntity, ParticleEffectNonInteractiveEntity 그리고 AnimatedSpriteNoninteractiveEntity. 대신, 나는 이것을 할 수있다 :

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);

내 그림자 수업: 나는 내 그린 모든 객체가 파생되는 추상 클래스가 있습니다. 일부 행동이 공유되기 때문에 추상 수업을 선택했습니다. 이것을 an으로 정의하는 것은 완벽하게 허용됩니다 상호 작용 대신, 그것이 당신의 코드에 맞지 않는다면.

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);
}

서브 클래스는 자체 드로우 로직을 정의합니다. 탱크 예에서 몇 가지 작업을 수행 할 수 있습니다.

  • 각 총알에 새 엔티티를 추가하십시오
  • 목록을 정의하는 탱크 클래스를 만들고 Draw ()를 재정의하여 총알을 반복합니다 (자신의 드로우 방법을 정의)
  • ListRudable을 만듭니다

다음은 목록 자체를 관리하는 방법에 대한 질문을 무시하고 ListDrawable의 구현 예입니다.

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);
        }
    }
}

다른 팁

프레임 워크와 같은 모크 그리고 코뿔소 조롱 특히 인터페이스가 필요하지 않습니다. 그들은 비정규 및/또는 추상 클래스도 조롱 할 수 있습니다. 게임은 추상적 인 클래스이므로 조롱하는 데 어려움이 없어야합니다 :-)

적어도 두 가지 프레임 워크로 주목해야 할 것은 방법이나 속성에 대한 기대치를 설정하려면 가상 또는 추상이어야한다는 것입니다. 그 이유는 생성 된 모의 인스턴스가 무시할 수 있어야하기 때문입니다. iAmcodemonkey가 언급 한 타입 록 나는 이것에 대한 방법을 가지고 있다고 생각하지만 TypeMock은 무료라고 생각하지는 않지만 내가 언급 한 두 가지는 그렇지 않다고 생각합니다.

제쳐두고, 당신은 또한 모의를 만들 필요없이 XNA 게임에 대한 단위 테스트를 만드는 데 도움이 될 수있는 나의 프로젝트를 확인할 수 있습니다. http://scurvytest.codeplex.com/

당신은 그것을 조롱 할 필요가 없습니다. 왜 가짜 게임 객체를 만들지 않습니까?

게임에서 상속하고 테스트에서 사용하려는 방법을 무시하여 필요한 메소드/속성에 대한 통조림 값 또는 단축키 계산을 반환하십시오. 그런 다음 가짜를 테스트에 전달하십시오.

프레임 워크를 조롱하기 전에 사람들은 자신의 모의/스터브/가짜를 굴 렸습니다. 아마도 빠르고 쉽지는 않지만 여전히 가능합니다.

인터페이스가 필요하지 않은 TypEmock이라는 도구를 사용할 수 있습니다. 더 일반적으로 따르는 방법은 게임에서 상속되는 새로운 클래스를 만드는 것입니다. 또한 게임 객체와 일치하는 인터페이스를 구현하는 것입니다. 그런 다음 해당 인터페이스에 대해 코딩하고 '사용자 정의'게임 객체를 전달할 수 있습니다.

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...
}

약간 지루하지만 조롱 가능성을 달성 할 수 있습니다.

당신이 그 이후로 신경 쓰지 않으면 나는 당신의 게시물에 돼지를 돌려 줄거야 나의 것 덜 활동적인 것 같고 이미 담당자를 라인에 올려 놓았습니다.)

귀하의 게시물 (Here & Xnaforum)을 읽을 때 더 접근하기 쉬운 프레임 워크와 완벽한 디자인이 아닙니다.

프레임 워크는 더 쉽게 확장되도록 설계 될 수 있습니다. 나는 믿기 어려운 시간을 보내고 있습니다 a의 주요 인수 성능은 인터페이스에 적중합니다. 나를 백업하기 위해 그의 동료 PERT 히트는 쉽게 회피 될 수 있다고 말합니다.
프레임 워크에는 이미 iupdatable 및 idrawable 인터페이스가 있습니다. 왜 끝까지 가지 않습니까?

반면에 나는 또한 내 (그리고 당신의) 디자인이 완벽하지 않다고 생각합니다. 내가 게임 객체에 의존하지 않는 경우, 나는 GraphicsDevice 객체에 크게 의존합니다. 나는 이것을 어떻게 우회 할 수 있는지 보게 될 것이다. 코드를 더 복잡하게 만들지 만 실제로 그 종속성을 깨뜨릴 수 있다고 생각합니다.

이와 같은 시작점을 위해 나는 XNA Winforms 샘플. 이 샘플을 모델로 사용하면 Winform에서 구성 요소를 시각화하는 한 가지 방법은 샘플에서 SpinningTriangleControl과 동일한 스타일로 컨트롤을 만드는 것 같습니다. 이것은 게임 인스턴스없이 XNA 코드를 렌더링하는 방법을 보여줍니다. 실제로 게임은 중요하지 않습니다. 중요한 것은 중요한 일입니다. 따라서 클래스와 다른 프로젝트에서 구성 요소의로드/드로우 로직을 가진 라이브러리 프로젝트를 만드는 것입니다. 각 환경에서 라이브러리 코드의 래퍼 인 제어 클래스 및 구성 요소 클래스를 만듭니다. 이렇게하면 테스트 코드가 복제되지 않았으며 두 가지 시나리오에서 항상 실행 가능한 코드 작성에 대해 걱정할 필요가 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top