1

I'm aware that it's "not allowed"; I did this by accident and it will thoroughly be removed from my final build. Obviously there's a good reason for that rule.

The weird thing is, it's in a unit testing component, and it still works perfectly in spite of the warning. I was filling a list with a few constructed instances of a class inheriting from MonoBehaviour, just to ensure that a function was doing what I wanted it to do, and I get this warning; but the test seems to run fine. Additionally, this is a warning, not an true error, which likely also has a reason.

Out of curiosity, as my understanding is clearly incomplete, can someone explain, and if possible provide a link to documentation explaining, why it is that Unity does not allow a behavior which it is clearly quite capable of? Why does it forbid this, and, in the event that the warning was ignored, what would be the drawbacks?

Thank you for completing my comprehension of it.

Michael Macha
  • 1,729
  • 1
  • 16
  • 25
  • 1
    None of the built-in properties like `gameObject` etc will work since there is no object attached to that object .. besides that there might be other undesired side effects like e.g. none of `Awake`, `Start` etc getting called at all – derHugo Jan 19 '22 at 16:38
  • Why not create the instance in an allowed way - even for the test - using e.g. `var component = new GameObject("some name"). AddComponent();` .. the you don't have to think about what could go wrong in the first place – derHugo Jan 19 '22 at 16:46
  • @derHugo what I'm working on is actually a sorting algorithm, to determine where items could reasonably be placed, without intersection, in a scene later; so I don't think it makes sense to worry about a new GameObject in a simplified unit test, I just want to be sure that they're being sorted properly. I'm more interested in this for my own edification, but thanks. – Michael Macha Jan 19 '22 at 17:22
  • Well does it make sense that a class is a `MonoBehaviour` if it actually is no behavior and not bound to a `GameObject`? Why not make your thing a normal class and not a component at all? – derHugo Jan 19 '22 at 18:23
  • Because it will be a component, it is a behavior, and I'm unit testing to ensure that my sorting function works. I'm sorry but I really don't know what you're missing there. There's no part of "change a large swath of code" which will benefit either testing or the final implementation. – Michael Macha Jan 23 '22 at 15:37
  • `ensure that my sorting function works` just doesn't sound like it is necessarily bound to a certain GameObject ... You can test this without doing anything in a Unity scene ... Maybe it would help if you describe the actual use case or share the code ... – derHugo Jan 23 '22 at 15:54
  • It needs to be in a Unity scene because the product is a Unity scene. That's pretty straightforward for an engineering test. Also, the question was answered a while ago, so I'm not sure why I should belabor it. – Michael Macha Jan 23 '22 at 16:32
  • Well the answer is to what goes wrong .. my approach would be how to make sure you don't have to worry about it at all ^^ if you are testing a sorting algorithm .. then write it and test it in a way where it only fulfills that single purpose: sorting. This has nothing to do with a scene. If however you really want a MonoBehaviour then instantiate it in the correct way according to the purpose of a MonoBehaviour ^^ – derHugo Jan 23 '22 at 16:42
  • @derHugo I don't think you're understanding me here. What you're suggesting is unprofessional testing--I am testing it in Unity with Monobehaviours; doing anything at all, anywhere else, is not testing in a Unity environment. I'm concerned about it for my own edification on the subject. I can't and wouldn't stop you, but you seem to lack a basic understanding of the original question, and I would much appreciate it if you would drop this stream of comments or at least provide an answer. Comments aren't for chatting. – Michael Macha Jan 25 '22 at 05:01
  • I don't think you're understanding me either, if you are not open for some discussion I guess you're on the wrong page ;) Ever heard of single responsibility? If for your test you basically say yourself you don't really need any of the MonoBehaviour functionality .. then it sounds to me your method you are testing is in the wrong place to begin with. So it should either be in an independent helper class you can simply instantiate using `new` or you make sure that you instantiate the MonoBehaviour they it is supposed to be. That's your two options and that would be professional. – derHugo Jan 25 '22 at 06:59
  • Let me suggest the book Debugging, by David J. Agans here. He's much more experienced at this stuff than me, with a career going back to the 1970s with a number of interesting war stories, and it's full of a number of famous incidents which will sway your opinion on that pretty readily. However, I don't really know why I should continue this conversation. – Michael Macha Jan 25 '22 at 13:42

2 Answers2

1

Unity has a component-based architecture. Any object that exists in a scene is represented by a GameObject which has one or more Component objects attached to it.

Components frequently change the behavior or appearance of the GameObject that they are attached to. In some cases, Components also reference or depend on each other. As an example, RigidBody and Collider components tend to be used in tandem.

MonoBehaviour scripts are also derived from the Component class. You can potentially create a behavior object using new, but it won't be attached to any GameObject and therefore won't properly exist in the scene. This is likely to lead to errors:

  • Built-in events may not work consistently. For example, Awake, Start, Update, or OnCollisionEnter.
  • Built-in references won't work at all. For example, gameObject, transform, or the AddComponent and GetComponent family of functions.
  • Unsafe for other components to interact with this component in a standard way.
  • Scene transitions are likely to compound the problem, since your orphaned script won't be attached to anything in the scene.

You do have some other options, though.

You can create a new GameObject, and then attach your script to it. This is a common workflow for scripts that will be managing game state for an entire scene (or across multiple scenes). This may fall under a singleton pattern.

You can also create classes that do not derive from MonoBehaviour, if you need those classes to be usable outside of a scene.

rutter
  • 11,242
  • 1
  • 30
  • 46
  • 1
    So what you're saying is that it's less impossible-to-compile and more that it's an abuse of what the code is intended to be used for? That does make sense. What I'm doing ultimately is a sort algorithm used for instantiating these properly in my scene, so given that I remove them when I'm done with the test, I doubt it will be an issue. – Michael Macha Jan 19 '22 at 17:22
1

While this is an old thread, part of it seems to have remained unaddressed.

I had a similar issue -- perhaps it will save someone else a headache: The warning came while running editor unit tests that made absolutely no reference to MonoBehaviours. This was confusing. The warning seemed to originate from within the NUnit.Framework and led to a script not written by me.

After much ado, I figured out that the class containing the tests was still inheriting from MonoBehaviour (since that was part of the template for a new script). Removing that inheritance fixed the issue.

PhilippR
  • 11
  • 1