टीएल; डीआर मुझे एक स्टेटफुल फ्रेमवर्क के भीतर काम करते समय स्वचालित इकाई परीक्षण को सरल बनाने के लिए तकनीकों की पहचान करने में मदद की आवश्यकता है।
पृष्ठभूमि:
मैं वर्तमान में टाइपस्क्रिप्ट और फेजर फ्रेमवर्क में एक खेल लिख रहा हूं । फेजर खुद को HTML5 गेम फ्रेमवर्क के रूप में वर्णित करता है जो आपके कोड की संरचना को प्रतिबंधित करने के लिए जितना संभव हो उतना कम प्रयास करता है। यह कुछ ट्रेड-ऑफ्स के साथ आता है, अर्थात् एक ईश्वर-वस्तु Phaser.Game मौजूद है जो आपको सब कुछ एक्सेस करने देता है: कैश, भौतिकी, गेम स्टेट्स, और बहुत कुछ।
यह स्थितित्मकता बहुत सारी कार्यक्षमता का परीक्षण करना कठिन बनाती है, जैसे कि मेरा तिलमप। आइए एक उदाहरण देखें:
यहाँ मैं परीक्षण कर रहा हूँ कि मेरी टाइल की परतें सही हैं या नहीं और मैं अपने तिलमप के भीतर की दीवारों और प्राणियों की पहचान कर सकता हूँ:
export class TilemapTest extends tsUnit.TestClass {
constructor() {
super();
this.map = this.mapLoader.load("maze", this.manifest, this.mazeMapDefinition);
this.parameterizeUnitTest(this.isWall,
[
[{ x: 0, y: 0 }, true],
[{ x: 1, y: 1 }, false],
[{ x: 1, y: 0 }, true],
[{ x: 0, y: 1 }, true],
[{ x: 2, y: 0 }, false],
[{ x: 1, y: 3 }, false],
[{ x: 6, y: 3 }, false]
]);
this.parameterizeUnitTest(this.isCreature,
[
[{ x: 0, y: 0 }, false],
[{ x: 2, y: 0 }, false],
[{ x: 1, y: 3 }, true],
[{ x: 4, y: 1 }, false],
[{ x: 8, y: 1 }, true],
[{ x: 11, y: 2 }, false],
[{ x: 6, y: 3 }, false]
]);
कोई फर्क नहीं पड़ता कि मैं क्या करता हूं, जैसे ही मैं नक्शा बनाने की कोशिश करता हूं, फेजर आंतरिक रूप से इसे कैश कहता है, जो केवल रनटाइम के दौरान आबादी है।
मैं पूरे खेल को लोड किए बिना इस परीक्षा का आह्वान नहीं कर सकता।
एक जटिल समाधान एक एडेप्टर या प्रॉक्सी लिखना हो सकता है जो केवल मानचित्र बनाता है जब हमें इसे स्क्रीन पर प्रदर्शित करने की आवश्यकता होती है। या मैं खुद को केवल उन परिसंपत्तियों को लोड करके खेल को आबाद कर सकता हूं जिनकी मुझे जरूरत है और फिर केवल विशिष्ट परीक्षण वर्ग या मॉड्यूल के लिए इसका उपयोग कर रहा हूं।
मैंने चुना कि मुझे जो लगता है वह अधिक व्यावहारिक है, लेकिन इसका विदेशी समाधान है। मेरे खेल की लोडिंग और उसके वास्तविक खेल के बीच, मैंने इसमें एक शर्म की बात TestState
है कि सभी परिसंपत्तियों और पहले से लोड किए गए डेटा के साथ परीक्षण चलाता है।
यह अच्छा है, क्योंकि मैं अपनी सभी कार्यक्षमता का परीक्षण कर सकता हूं, लेकिन यह भी अनकूल है, क्योंकि यह तकनीकी एकीकरण परीक्षण है और एक आश्चर्य है कि क्या मैं सिर्फ स्क्रीन पर नहीं देख सकता हूं और देख सकता हूं कि क्या दुश्मन प्रदर्शित होते हैं। वास्तव में, नहीं, उन्हें एक आइटम के रूप में गलत पहचान दिया गया था (एक बार पहले ही हो चुका है) या बाद में परीक्षणों में- उन्हें शायद उनकी मृत्यु से जुड़ी घटनाओं को नहीं दिया गया है।
मेरा सवाल - क्या यह आम जैसी परीक्षा-अवस्था में चमक रहा है? क्या विशेष रूप से जावास्क्रिप्ट वातावरण में बेहतर दृष्टिकोण हैं, जिनके बारे में मुझे जानकारी नहीं है?
एक और उदाहरण:
ठीक है, यह बताने के लिए कि क्या हो रहा है, यह बताने के लिए एक अधिक ठोस उदाहरण है:
export class Tilemap extends Phaser.Tilemap {
// layers is already defined in Phaser.Tilemap, so we use tilemapLayers instead.
private tilemapLayers: TilemapLayers = {};
// A TileMap can have any number of layers, but
// we're only concerned about the existence of two.
// The collidables layer has the information about where
// a Player or Enemy can move to, and where he cannot.
private CollidablesLayer = "Collidables";
// Triggers are map events, anything from loading
// an item, enemy, or object, to triggers that are activated
// when the player moves toward it.
private TriggersLayer = "Triggers";
private items: Array<Phaser.Sprite> = [];
private creatures: Array<Phaser.Sprite> = [];
private interactables: Array<ActivatableObject> = [];
private triggers: Array<Trigger> = [];
constructor(json: TilemapData) {
// First
super(json.game, json.key);
// Second
json.tilesets.forEach((tileset) => this.addTilesetImage(tileset.name, tileset.key), this);
json.tileLayers.forEach((layer) => {
this.tilemapLayers[layer.name] = this.createLayer(layer.name);
}, this);
// Third
this.identifyTriggers();
this.tilemapLayers[this.CollidablesLayer].resizeWorld();
this.setCollisionBetween(1, 2, true, this.CollidablesLayer);
}
मैं तीन भागों से अपने तिलमाप का निर्माण करता हूं:
- मानचित्र
key
manifest
ब्यौरा सभी परिसंपत्तियों (tilesheets और spritesheets) मानचित्र के लिए आवश्यक- एक
mapDefinition
जो टिलेमैप की संरचना और परतों का वर्णन करता है।
पहले, मुझे फेजर के भीतर तिलमैप के निर्माण के लिए सुपर को कॉल करना होगा। यह वह हिस्सा है जो उन सभी कॉल्स को कैश करने के लिए आमंत्रित करता है क्योंकि यह वास्तविक परिसंपत्तियों को देखने की कोशिश करता है न कि केवल परिभाषित कीज़ में manifest
।
दूसरा, मैं टाइल्स और टाइल की परतों को तिलमाप के साथ जोड़ता हूं। यह अब मैप रेंडर कर सकता है।
तीसरा, मैं पुनरावृति मेरी परतों के माध्यम से और किसी भी विशेष वस्तुओं पाते हैं कि मैं नक्शे से बाहर निकालना चाहते हैं: Creatures
, Items
, Interactables
और इसके आगे। मैं बाद में उपयोग के लिए इन वस्तुओं को बनाता और संग्रहीत करता हूं।
मेरे पास वर्तमान में एक अपेक्षाकृत सरल एपीआई है जो मुझे इन संस्थाओं को खोजने, हटाने, अद्यतन करने देता है:
wallAt(at: TileCoordinates) {
var tile = this.getTile(at.x, at.y, this.CollidablesLayer);
return tile && tile.index != 0;
}
itemAt(at: TileCoordinates) {
return _.find(this.items, (item: Phaser.Sprite) => _.isEqual(this.toTileCoordinates(item), at));
}
interactableAt(at: TileCoordinates) {
return _.find(this.interactables, (object: ActivatableObject) => _.isEqual(this.toTileCoordinates(object), at));
}
creatureAt(at: TileCoordinates) {
return _.find(this.creatures, (creature: Phaser.Sprite) => _.isEqual(this.toTileCoordinates(creature), at));
}
triggerAt(at: TileCoordinates) {
return _.find(this.triggers, (trigger: Trigger) => _.isEqual(this.toTileCoordinates(trigger), at));
}
getTrigger(name: string) {
return _.find(this.triggers, { name: name });
}
यह कार्यक्षमता है जिसे मैं जांचना चाहता हूं। यदि मैं टाइल परत या टाइलसेट नहीं जोड़ता हूं, तो नक्शा प्रस्तुत नहीं होगा, लेकिन मैं इसका परीक्षण करने में सक्षम हो सकता हूं। हालाँकि, यहां तक कि सुपर (...) को कॉल करना संदर्भ-विशिष्ट या स्टेटफुल लॉजिक को संदर्भित करता है जिसे मैं अपने परीक्षणों में अलग नहीं कर सकता।
new Tilemap(...)
फेजर अपने कैश में खोदना शुरू करता हूं । मुझे लगता है कि टालना होगा, लेकिन इसका मतलब है कि मेरा तिलमप दो राज्यों में है, एक जो खुद को ठीक से प्रस्तुत नहीं कर सकता है, और पूरी तरह से निर्मित है।