- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 Github 上有以下开源项目 ( game project )。我目前正在尝试对我使用 MSTest 框架编写的代码进行单元测试,但所有测试都返回相同的错误消息:“未处理的异常:System.Security.SecurityException:ECall 方法必须打包到系统模块中。”当我尝试使用 NUnit 模板进行单元测试时,发生了这种情况。
我浏览过 ECall methods post must be packaged找到一些答案,但我没有,因为OP说他的解决方案在调试器区域内有效,但在调试器区域外无效。就我而言,在查看该帖子时,OP 的问题尚未解决。
之后,我将 UnityTestTools 框架导入到我的项目中。我认为这很容易,因为它基于 NUnit 框架。事实证明没有。该测试本身是相当基础的。我有一个名为 BaseCharacterClass:MonoBehavior 的基类,除其他外,它还具有 BaseCharacterStats 类型的属性。在统计数据中,有一个CharacterHealth类型的对象,它负责照顾玩家的健康状况。
现在,我有以下两个堆栈跟踪,当我在测试中尝试以下操作时,我似乎没有得到它们。
单元测试 (NUNIT)
使用 new 关键字创建 MonoBehavior 对象
[Test]
[Category("Mock Character")]
public void Mock_Character_With_No_Health()
{
var mock = new MoqBaseCharacter ();
Assert.NotNull (mock.BaseStats);
Assert.NotNull (mock.BaseStats.Health);
Assert.LessOrEqual (0, mock.BaseStats.Health.CurrentHealth);
}
//This is not the full file
//There "2" classes: 1 for holding tests and that Mock object
public MoqBaseCharacter()
{
this.BaseStats = new BaseCharacterStats ();
this.BaseStats.Health = new CharacterHealth (0);
}
堆栈跟踪:
Mock_Character_With_No_Health (0.047s) --- System.NullReferenceException : Object reference not set to an instance of an object --- at Assets.Scripts.CharactersUtil.CharacterHealth..ctor (Int32 sh) [0x0002f] in C:\Users\Kevin\Documents\AndroidPC_Prototype\PC_Augmented_Tactics_Demo\Assets\Scripts\CharactersUtil\CharacterHealth.cs:29
at UnityTest.MoqBaseCharacter..ctor () [0x00011] in C:\Users\Kevin\Documents\AndroidPC_Prototype\PC_Augmented_Tactics_Demo\Assets\UnityTestTools\Examples\UnitTestExamples\Editor\SampleTests.cs:14
at UnityTest.SampleTests.Mock_Character_With_No_Health () [0x00000] in C:\Users\Kevin\Documents\AndroidPC_Prototype\PC_Augmented_Tactics_Demo\Assets\UnityTestTools\Examples\UnitTestExamples\Editor\SampleTests.cs:32
使用 NSubstitute.For
[Test]
[Category("Mock Character")]
public void Mock_Character_With_No_Health()
{
var mock = NSubstitute.Substitute.For<MoqBaseCharacter> ();
Assert.NotNull (mock.BaseStats);
Assert.NotNull (mock.BaseStats.Health);
Assert.LessOrEqual (0, mock.BaseStats.Health.CurrentHealth);
}
堆栈跟踪
Mock_Character_With_No_Health (0.137s) --- System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ----> System.NullReferenceException : Object reference not set to an instance of an object --- at System.Reflection.MonoCMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0012c] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:519
at System.Reflection.MonoCMethod.Invoke (BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:528
at System.Activator.CreateInstance (System.Type type, BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x001b8] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Activator.cs:338
at System.Activator.CreateInstance (System.Type type, System.Object[] args, System.Object[] activationAttributes) [0x00000] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Activator.cs:268
at System.Activator.CreateInstance (System.Type type, System.Object[] args) [0x00000] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Activator.cs:263
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance (System.Type proxyType, System.Collections.Generic.List`1 proxyArguments, System.Type classToProxy, System.Object[] constructorArguments) [0x00000] in :0
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy (System.Type classToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options, System.Object[] constructorArguments, Castle.DynamicProxy.IInterceptor[] interceptors) [0x00000] in :0
at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.CreateProxyUsingCastleProxyGenerator (System.Type typeToProxy, System.Type[] additionalInterfaces, System.Object[] constructorArguments, IInterceptor interceptor, Castle.DynamicProxy.ProxyGenerationOptions proxyGenerationOptions) [0x00000] in :0
at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.GenerateProxy (ICallRouter callRouter, System.Type typeToProxy, System.Type[] additionalInterfaces, System.Object[] constructorArguments) [0x00000] in :0
at NSubstitute.Proxies.ProxyFactory.GenerateProxy (ICallRouter callRouter, System.Type typeToProxy, System.Type[] additionalInterfaces, System.Object[] constructorArguments) [0x00000] in :0
at NSubstitute.Core.SubstituteFactory.Create (System.Type[] typesToProxy, System.Object[] constructorArguments, SubstituteConfig config) [0x00000] in :0
at NSubstitute.Core.SubstituteFactory.Create (System.Type[] typesToProxy, System.Object[] constructorArguments) [0x00000] in :0
at NSubstitute.Substitute.For (System.Type[] typesToProxy, System.Object[] constructorArguments) [0x00000] in :0
at NSubstitute.Substitute.For[MoqBaseCharacter] (System.Object[] constructorArguments) [0x00000] in :0
at UnityTest.SampleTests.Mock_Character_With_No_Health () [0x00000] in C:\Users\Kevin\Documents\AndroidPC_Prototype\PC_Augmented_Tactics_Demo\Assets\UnityTestTools\Examples\UnitTestExamples\Editor\SampleTests.cs:32 --NullReferenceException
at Assets.Scripts.CharactersUtil.CharacterHealth..ctor (Int32 sh) [0x0002f] in C:\Users\Kevin\Documents\AndroidPC_Prototype\PC_Augmented_Tactics_Demo\Assets\Scripts\CharactersUtil\CharacterHealth.cs:29
at UnityTest.MoqBaseCharacter..ctor () [0x00011] in C:\Users\Kevin\Documents\AndroidPC_Prototype\PC_Augmented_Tactics_Demo\Assets\UnityTestTools\Examples\UnitTestExamples\Editor\SampleTests.cs:14
at Castle.Proxies.MoqBaseCharacterProxy..ctor (ICallRouter , Castle.DynamicProxy.IInterceptor[] ) [0x00000] in :0
at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (object,object[],System.Exception&)
at System.Reflection.MonoCMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00119] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:513
免责声明
快速阅读NSubstitute告诉我,我应该更好地使用接口(interface)来代替...在我的情况下,我真的不知道接口(interface)如何更适合我的代码。如果有人对此有想法而不是使用 new 关键字,我会全力以赴!最后,这是 BaseCharacter、BaseStats 和 Health 的源代码
基本角色实现
using System;
using UnityEngine;
using System.Collections.Generic;
using JetBrains.Annotations;
using Random = System.Random;
namespace Assets.Scripts.CharactersUtil
{
public class BaseCharacterClass : MonoBehaviour
{
//int[] basicUDLRMovementArray = new int[4];
public List<BaseCharacterClass> CurrentEnnemies;
public int StartingHealth = 500;
public BaseCharacterStats BaseStats { get; set; }
// Use this for initialization
private void Start()
{
BaseStats = new BaseCharacterStats {Health = new CharacterHealth(StartingHealth)}; //Testing purposes
BaseStats.ChanceForCriticalStrike = new Random().Next(0,BaseStats.CriticalStrikeCounter);
}
// Update is called once per frame
private void Update()
{
//ExecuteBasicMovement();
}
//During an attack with any kind of character
//TODO: Make sure that people from the same team cannot attack themselves (friendly fire)
private void OnTriggerEnter([NotNull] Collider other)
{
if (other == null) throw new ArgumentNullException(other.tag);
Debug.Log("I'm about to receive some damage");
var characterStats = other.gameObject.GetComponent<BaseCharacterClass>().BaseStats;
var heathToAddOrRemove = other.gameObject.tag == "Healer" || other.gameObject.tag == "AIHealer" ? characterStats.Power : -1 * characterStats.Power;
characterStats.Health.TakeDamageFromCharacter((int)heathToAddOrRemove);
Debug.Log("I should have received damage from a bastard");
if (characterStats.Health.CurrentHealth == 500)
{
Debug.Log("This is a mistake, I believe I'm a god! INVICIBLE");
}
}
/*
public void ExecuteBasicMovement()
{
var move = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0);
transform.position += move * BaseStats.Speed * Time.deltaTime;
}
//TODO: Make sure players moves correctly within the environment per cases
public void ExecuteMovementPerCase()
{
}
*/
public bool CanDoExtraDamage()
{
if (BaseStats.ChanceForCriticalStrike*BaseStats.Luck < 50) return false;
BaseStats.CriticalStrikeCounter--;
BaseStats.ChanceForCriticalStrike = new Random().Next(0, BaseStats.CriticalStrikeCounter);
BaseStats.AjustCriticalStrikeChances();
return true;
}
}
}
基础统计数据
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
namespace Assets.Scripts.CharactersUtil
{
public class BaseCharacterStats
{
public float Power { get; set; }
public float Defense { get; set; }
public float Agility { get; set; }
public float Speed { get; set; }
public float MagicPower { get; set; }
public float MagicResist { get; set; }
public int ChanceForCriticalStrike;
public int Luck { get; set; }
public int CriticalStrikeCounter = 20;
public int TemporaryDefenseBonusValue;
private Random _randomValueGenerator;
public BaseCharacterStats()
{
_randomValueGenerator= new Random();
}
[NotNull]
public CharacterHealth Health
{
get { return _health; }
set { _health = value; }
}
private CharacterHealth _health;
public void AjustCriticalStrikeChances()
{
if (CriticalStrikeCounter <= 5)
{
CriticalStrikeCounter = 5;
}
}
public int DetermineDefenseBonusForTurn()
{
TemporaryDefenseBonusValue = _randomValueGenerator.Next(10,20);
return TemporaryDefenseBonusValue;
}
}
}
健康
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.UI;
namespace Assets.Scripts.CharactersUtil
{
public class CharacterHealth {
public int StartingHealth { get; set; }
public int CurrentHealth { get; set; }
public Slider HealthSlider { get; set; }
public bool isDead;
public Color MaxHealthColor = Color.green;
public Color MinHealthColor = Color.red;
private int _counter;
private const int MaxHealth = 200;
public Image Fill;
private void Awake() {
//HealthSlider = GameObject.GetComponent<Slider>();
_counter = MaxHealth; // just for testing purposes
}
// Use this for initialization
public CharacterHealth(int sh)
{
StartingHealth = sh;
CurrentHealth = StartingHealth;
HealthSlider.wholeNumbers = true;
HealthSlider.minValue = 0f;
HealthSlider.maxValue = StartingHealth;
HealthSlider.value = CurrentHealth;
}
public void Start()
{
HealthSlider.wholeNumbers = true;
HealthSlider.minValue = 0f;
HealthSlider.maxValue = MaxHealth;
HealthSlider.value = MaxHealth;
}
public void TakeDamageFromCharacter([NotNull] BaseCharacterClass baseCharacter)
{
CurrentHealth -= (int)baseCharacter.BaseStats.Power;
HealthSlider.value = CurrentHealth;
UpdateHealthBar ();
if (CurrentHealth <= 0)
isDead = true;
}
public void TakeDamageFromCharacter(int characterStrength)
{
CurrentHealth -= characterStrength;
HealthSlider.value = CurrentHealth;
UpdateHealthBar ();
if (CurrentHealth <= 0)
isDead = true;
}
public void RestoreHealth(BaseCharacterClass bs)
{
CurrentHealth += (int)bs.BaseStats.Power;
HealthSlider.value = CurrentHealth;
UpdateHealthBar ();
}
public void RestoreHealth(int characterStrength)
{
CurrentHealth += characterStrength;
HealthSlider.value = CurrentHealth;
UpdateHealthBar ();
}
public void UpdateHealthBar() {
Fill.color = Color.Lerp(MinHealthColor, MaxHealthColor, (float)CurrentHealth / MaxHealth);
}
}
}
最佳答案
还有另一个选项可以在不调用构造函数的情况下对 MonoBehaviours 进行单元测试(使用 FormatterServices)。这是一个创建可测试的 MonoBehaviours 的小帮助器类:
public static class TestableObjectFactory {
public static T Create<T>() {
return FormatterServices.GetUninitializedObject(typeof(T)).CastTo<T>();
}
}
用法:
var testableObject = TestableObjectFactory.Create<MyMonoBehaviour>();
testableObject.Test();
关于c# - 如何在 Unity 游戏引擎平台上的单元测试中实例化 MonoBehaviour 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33094653/
我正在尝试编写一个程序来列出网络上所有设备的 IP 地址。其主要组成部分之一是能够 ping 设备。这个程序必须在 Linux、Windows 和 Mac 上运行,所以我选择了 Boost 库。 我设
如果我使用 Google 的 Jquery 加载脚本链接,那么如果用户的缓存中已经有该文件,那么当页面加载时,用户计算机是否仍会以任何方式与 Google 联系? 例子: 最佳答案 根据浏览器的缓存
我想在我的 ruby 代码中 ping 一个站点,发现 net-ping 是一个很好的库来执行此操作。不幸的是,当我尝试 gem install net-ping 时出现以下错误: C:>gem
我有一个表(test_matches),其中记录了几场比赛的结果,按日期排序。 GHFT = 目标主队全职。GAFT = 全职客场进球队。 CREATE TABLE `test_matches` (
我正在使用 phing对于一个项目的一些自动构建过程,我想知道:我怎样才能通过电子邮件获得完整的日志? 当我通过命令行启动 phing 时,会显示构建日志;我想要它: 通过电子邮件发送, 给几个收件人
尝试根据 GF 和 GA 创建一个新列“Results”。想知道如何通过定义函数和条件语句来做到这一点。以下是我对一行的初步尝试,但无法弄清楚如何将其应用于所有行,非常感谢您的帮助! 日期地点对手GF
我是一名优秀的程序员,十分优秀!