You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
15 KiB
336 lines
15 KiB
using System;
|
|
using System.Collections;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.TestTools;
|
|
|
|
namespace Tests
|
|
{
|
|
public class ShopUnitTests
|
|
{
|
|
private ShopView shopView; //This is the grid buy view we want to test
|
|
private SellViewGrid sellView;
|
|
private ShopView upgradeView;
|
|
|
|
//Setup the test scene
|
|
[OneTimeSetUp]
|
|
public void LoadShopScene()
|
|
{
|
|
// Load the Scene to do unit test. In the scope of this project, this is fine. In a more complicated project, a game scene could take
|
|
// a long time to load, in which case it's better to create test scenes to do unit tests
|
|
SceneManager.LoadScene(0);
|
|
}
|
|
|
|
//Setup the unit tests here
|
|
[UnitySetUp]
|
|
public IEnumerator SetupTests()
|
|
{
|
|
yield return
|
|
null; //yield return null skips one frame, this is to make sure that this happens after the scene is loaded
|
|
|
|
//The shop scene only contains one grid buy view, we use Resources.FindObjectsOfTypeAll to get the reference to it,
|
|
//Resources.FFindObjectsOfTypeAll is used instead of GameObject.Find because the later can't find disabled objects
|
|
var shops = Resources.FindObjectsOfTypeAll<ShopViewGrid>();
|
|
shopView = shops[2]; // For some reason this reverses it. We just want to hardcode it for this scene, no annoying for loops to compare
|
|
upgradeView = shops[1];
|
|
|
|
sellView = Resources.FindObjectsOfTypeAll<SellViewGrid>()[0];
|
|
|
|
// Turn on all views so they function correctly. We do not care for the looks during unit tests, obviously.
|
|
sellView.gameObject.SetActive(true);
|
|
upgradeView.gameObject.SetActive(true);
|
|
//Active the gridBuyView game object to initialize the class, if we don't do this 'void Start()' won't be called
|
|
//You should active all the game objects that are involved in the test before testing the functions from their components
|
|
shopView.gameObject.SetActive(true);
|
|
}
|
|
|
|
// Use meaningful name for your test cases, this case tests if the ShopGridBuyView component has initialized its ShopModel property
|
|
[UnityTest]
|
|
public IEnumerator ShopGridBuyViewInitializedShopModel()
|
|
{
|
|
yield return null; //yield return null skips one frame, waits for the Unity scene to load
|
|
|
|
//now test if a ShopModel is assigned to gridBuyView
|
|
Assert.IsNotNull(shopView.ShopModel, "No Model is assigned in ShopView");
|
|
}
|
|
|
|
//This case tests if the grid buy view displays the correct amount of Items
|
|
[UnityTest,Order(1)] // Run this one first to see if we populated everything correctly
|
|
public IEnumerator ShopGridBuyViewDisplaysCorrectAmountOfItems()
|
|
{
|
|
yield return null; //yield return null skips one frame, waits for the Unity scene to load
|
|
|
|
//Now that the scene is loaded and the gridBuyView game object was activated in SetupTests(), we can use GameObject.Find
|
|
//to find the game object we want to test
|
|
GameObject gridItemsPanel = GameObject.Find("GridItemsPanel");
|
|
|
|
yield return
|
|
new WaitForEndOfFrame(); //Since we are testing how many items are displayed, we should use WaitForEndOfFrame to wait until the end of the frame,
|
|
//so that the view finished updating and rendering everything
|
|
|
|
yield return null;
|
|
int itemCount = gridItemsPanel.transform.childCount;
|
|
Assert.AreEqual(shopView.ShopModel.inventory.GetItemCount(), itemCount,
|
|
"The generated item count is not equal to shopModel's itemCount");
|
|
}
|
|
|
|
// This case tests if the shop model gets populated with items
|
|
[UnityTest,Order(0)] // Run this one before the view tests to see if the factory works
|
|
public IEnumerator ShopFactoryPopulatesShop()
|
|
{
|
|
yield return null; //yield return null skips one frame, waits for the Unity scene to load
|
|
|
|
//Now that the scene is loaded and the gridBuyView game object was activated in SetupTests(), we can use GameObject.Find
|
|
//to find the game object we want to test
|
|
var count = 0;
|
|
Assert.DoesNotThrow(delegate
|
|
{
|
|
count = shopView.ShopModel.inventory.GetItemCount();
|
|
});
|
|
Assert.Greater(count,1); // Having just one item probably means something went wrong and crashed
|
|
|
|
}
|
|
|
|
//This case tests if the buyModel can throw an ArgumentOutOfRangeException when it's asked to select an item by a negative
|
|
//index. Incorrect indexes can be generated from bugs in views or controllers, throwing the correct type of exceptions is
|
|
//better than failing silently for debugging. Your unit tests should cover exception handlings
|
|
[UnityTest]
|
|
public IEnumerator ShopModelThrowsExceptionsWhenSelectingNegativeIndex()
|
|
{
|
|
//yield return null skips one frame, waits for the Unity scene to load and buyModel to be assigned
|
|
yield return null;
|
|
|
|
//Creates a delegate that call gridBuyView.ShopModel.SelectItemByIndex(-1), the test runner will run the function, and
|
|
//check if an ArgumentOutOfRangeException is thrown, the unit test would fail if no ArgumentOutOfRangeException
|
|
//was thrown
|
|
Assert.Throws<System.ArgumentOutOfRangeException>(delegate
|
|
{
|
|
shopView.ShopModel.SelectItemByIndex(-1);
|
|
});
|
|
}
|
|
|
|
//This case tests whether info panels and selection highlights work correctly when a specific item is selected, while disabling correctly when it is unselected
|
|
[UnityTest]
|
|
public IEnumerator UpdateViewItemInfoPanelAndSelection()
|
|
{
|
|
yield return null;
|
|
|
|
var selectedItem = shopView.transform.Find("GridItemsPanel");
|
|
var active = selectedItem.GetComponentInChildren<ViewItemInfoPanel>(); // In grid view, one item panel will be active. That's the selected item!
|
|
shopView.ShopModel.SelectItemByIndex(shopView.ShopModel.GetSelectedItemIndex() + 1);
|
|
var newActive = selectedItem.GetComponentInChildren<ViewItemInfoPanel>();
|
|
|
|
Assert.AreNotSame(active, newActive,"Previous item is still selected!");
|
|
}
|
|
|
|
// This test case tests that either no item is selected, or exactly one item is selected
|
|
[UnityTest]
|
|
public IEnumerator NoMoreThanOneItemSelectedInView()
|
|
{
|
|
yield return null;
|
|
|
|
var selectedItem = shopView.transform.Find("GridItemsPanel");
|
|
var active = selectedItem.GetComponentsInChildren<ViewItemInfoPanel>(); // In grid view, one item panel will be active. That's the selected item!
|
|
|
|
Assert.Greater(2,active.Length,"Too many items selected!"); // Depending on what's up, either we want none or just one selected now
|
|
shopView.ShopModel.SelectItemByIndex(shopView.ShopModel.GetSelectedItemIndex() + 1);
|
|
shopView.ShopModel.SelectItemByIndex(shopView.ShopModel.GetSelectedItemIndex() + 1);
|
|
active = selectedItem.GetComponentsInChildren<ViewItemInfoPanel>(); // In grid view, one item panel will be active. That's the selected item!
|
|
UnityEngine.Assertions.Assert.AreEqual(active.Length,1,"Too many items or no item selected!"); // Now we definitely need one to be selected!
|
|
}
|
|
|
|
// This test case tests if the currently selected item disappears from the view when the buy model confirms the selection
|
|
[UnityTest]
|
|
public IEnumerator ModelSelectionRemovesViewItem()
|
|
{
|
|
yield return null;
|
|
var selectedItem = shopView.transform.Find("GridItemsPanel");
|
|
shopView.ShopModel.SelectItemByIndex(shopView.ShopModel.GetSelectedItemIndex() + 1);
|
|
|
|
yield return null;
|
|
var active = selectedItem.GetComponentInChildren<ViewItemInfoPanel>(); // In grid view, one item panel will be active. That's the selected item!
|
|
shopView.ShopModel.ConfirmSelectedItem();
|
|
yield return null;
|
|
UnityEngine.Assertions.Assert.IsTrue(active == null,"Selected item view was not destroyed when bought!"); // Now we definitely need one to be selected!
|
|
}
|
|
|
|
// Tests if the player inventory doesn't allow to overdraw money. We test on shop inventory even though that one's money's technically irrelevant, but works the same on all
|
|
[UnityTest]
|
|
public IEnumerator InventoryDoesNotAllowExceedingTransactions()
|
|
{
|
|
yield return null;
|
|
// So if we pay too much, we expect an exception
|
|
Assert.Throws<InsufficientMoneyException>(delegate
|
|
{
|
|
shopView.ShopModel.inventory.ChangeBalance(-shopView.ShopModel.inventory.Money -
|
|
1); // Pay one money more than it's got!
|
|
});
|
|
}
|
|
|
|
// Tests if transaction changes actually change an inventory's balance
|
|
[UnityTest]
|
|
public IEnumerator InventoryCorrectlyHandlesBalanceChange()
|
|
{
|
|
yield return null;
|
|
|
|
var moneyBefore = shopView.ShopModel.inventory.Money;
|
|
shopView.ShopModel.inventory.ChangeBalance(-shopView.ShopModel.inventory.Money); // Spend all our money!
|
|
|
|
Assert.AreNotEqual(moneyBefore,shopView.ShopModel.inventory.Money);
|
|
Assert.Zero(shopView.ShopModel.inventory.Money);
|
|
shopView.ShopModel.inventory.ChangeBalance(moneyBefore + 1); // For good measure, re-add all money plus a one money bonus
|
|
|
|
Assert.AreEqual(moneyBefore + 1,shopView.ShopModel.inventory.Money);
|
|
}
|
|
|
|
// Tests if a model throws an error when trying to select an item directly that isn't part of it
|
|
[UnityTest]
|
|
public IEnumerator ModelSelectionErrorIfInvalid()
|
|
{
|
|
yield return null;
|
|
|
|
Assert.Throws<ArgumentException>(delegate
|
|
{
|
|
shopView.ShopModel.SelectItem(new ItemPotion("some name","invalidIcon",5,2,PotionType.Healing));
|
|
});
|
|
}
|
|
|
|
// Tests if a model selects an item correctly when it's valid
|
|
[UnityTest]
|
|
public IEnumerator ModelSelectionIndexCorrectIfValid()
|
|
{
|
|
yield return null;
|
|
|
|
var item = shopView.ShopModel.GetSelectedItem();
|
|
shopView.ShopModel.SelectItemByIndex(shopView.ShopModel.GetSelectedItemIndex() + 1);
|
|
|
|
Assert.AreNotSame(item,shopView.ShopModel.GetSelectedItem());
|
|
|
|
Assert.DoesNotThrow(delegate
|
|
{
|
|
shopView.ShopModel.SelectItem(item);
|
|
});
|
|
|
|
Assert.AreSame(item,shopView.ShopModel.GetSelectedItem());
|
|
}
|
|
|
|
// Tests if a buy model removes an item on confirmation, and then selects another one
|
|
[UnityTest]
|
|
public IEnumerator BuyModelConfirmationRemovesItemAndSelectsNew()
|
|
{
|
|
yield return null;
|
|
|
|
var item = shopView.ShopModel.GetSelectedItem();
|
|
shopView.ShopModel.ConfirmSelectedItem();
|
|
|
|
Assert.AreNotSame(item,shopView.ShopModel.GetSelectedItem());
|
|
|
|
Assert.Throws<ArgumentException>(delegate
|
|
{
|
|
shopView.ShopModel.SelectItem(item);
|
|
});
|
|
|
|
Assert.AreNotSame(item,shopView.ShopModel.GetSelectedItem());
|
|
}
|
|
|
|
// Tests if a buy model removes money from an inventory it buys from
|
|
[UnityTest]
|
|
public IEnumerator BuyingItemCostsMoney()
|
|
{
|
|
yield return null;
|
|
|
|
var money = sellView.ShopModel.inventory.Money; // In the scene setup, sellView happens to reference the player inventory the shop trades with
|
|
Assert.DoesNotThrow(delegate
|
|
{
|
|
shopView.ShopModel.ConfirmSelectedItem();
|
|
});
|
|
|
|
Assert.Less(sellView.ShopModel.inventory.Money,money);
|
|
}
|
|
|
|
// Tests if a sell model gains money from selling
|
|
[UnityTest]
|
|
public IEnumerator SellingItemGivesMoney()
|
|
{
|
|
yield return null;
|
|
|
|
var money = sellView.ShopModel.inventory.Money; // In the scene setup, sellView happens to reference the player inventory the shop trades with
|
|
Assert.DoesNotThrow(delegate
|
|
{
|
|
sellView.ShopModel.ConfirmSelectedItem();
|
|
});
|
|
|
|
Assert.Greater(sellView.ShopModel.inventory.Money,money);
|
|
}
|
|
|
|
// Tests if selling removes the item from the sell inventory
|
|
[UnityTest]
|
|
public IEnumerator SellingItemRemovesFromInventory()
|
|
{
|
|
yield return null;
|
|
|
|
var item = sellView.ShopModel.GetSelectedItem();
|
|
sellView.ShopModel.ConfirmSelectedItem();
|
|
|
|
Assert.AreNotSame(item,sellView.ShopModel.GetSelectedItem());
|
|
|
|
Assert.Throws<ArgumentException>(delegate
|
|
{
|
|
sellView.ShopModel.SelectItem(item);
|
|
});
|
|
|
|
Assert.AreNotSame(item,sellView.ShopModel.GetSelectedItem());
|
|
}
|
|
|
|
// Tests if upgrading an item does not remove it
|
|
[UnityTest]
|
|
public IEnumerator UpgradingKeepsInInventory()
|
|
{
|
|
yield return null;
|
|
|
|
var item = upgradeView.ShopModel.GetSelectedItem();
|
|
upgradeView.ShopModel.ConfirmSelectedItem();
|
|
|
|
Assert.AreSame(item,upgradeView.ShopModel.GetSelectedItem());
|
|
|
|
Assert.DoesNotThrow(delegate
|
|
{
|
|
upgradeView.ShopModel.SelectItem(item);
|
|
});
|
|
|
|
Assert.AreSame(item,upgradeView.ShopModel.GetSelectedItem());
|
|
}
|
|
|
|
// Tests if upgrading costs money
|
|
[UnityTest]
|
|
public IEnumerator UpgradingCostsMoney()
|
|
{
|
|
yield return null;
|
|
|
|
var money = upgradeView.ShopModel.inventory.Money; // In the scene setup, sellView happens to reference the player inventory the shop trades with
|
|
Assert.DoesNotThrow(delegate
|
|
{
|
|
upgradeView.ShopModel.ConfirmSelectedItem();
|
|
});
|
|
|
|
Assert.Less(upgradeView.ShopModel.inventory.Money,money);
|
|
}
|
|
|
|
// Tests if upgrading improves an item's stats
|
|
[UnityTest]
|
|
public IEnumerator UpgradingImprovesStats()
|
|
{
|
|
yield return null;
|
|
|
|
var item = upgradeView.ShopModel.GetSelectedItem(); // In the scene setup, sellView happens to reference the player inventory the shop trades with
|
|
var stats = item.GetStats(); // Stats right now are turned into a generic string type. If we get a different one post-upgrade, it should've worked
|
|
Assert.DoesNotThrow(delegate
|
|
{
|
|
upgradeView.ShopModel.ConfirmSelectedItem();
|
|
});
|
|
|
|
Assert.AreNotEqual(stats,upgradeView.ShopModel.GetSelectedItem().GetStats());
|
|
}
|
|
}
|
|
}
|