UnityEngine.Object instances have no name property in test - unit-testing

Assigning names to my objects (like the ones returned from the global Instantiate method) is breaking my tests. Anyone have any ideas for how to get around such things in test?
using System;
using NUnit.Framework;
using UnityEngine;
[TestFixture()]
public class BoardSpec{
[Test()]
public void NamePropertyWorks(){
var obj = new UnityEngine.Object();
obj.name = "object name";
}
}
The error I'm receiving: System.MissingMethodException : Cannot find the requested method.
The first line of the stack trace gives: at (wrapper managed-to-native) UnityEngine.Object:set_name (string)
Unity 5.2.0f3, running tests in MonoDevelop-Unity 4.0.1 on osx
_____update 9/20______
It sounds like creating new Objects is not recommended, but this code fails with the same error:
[Test()]
public void ScriptableObjectNamePropertyWorks(){
var obj = new ScriptableObject();
obj.name = "object name";
}

Short answer: Never create nor inherit directly form UnityEngine.Object, use ScriptableObject instead
Doing something like (new UnityEngine.Object()).name = "text" will always throw a null reference exception, as I'll explain below. From there to the System.MissingMethodException you are getting, it depends on the inner workings of NUnit.
Unity uses UnityEngine.Object in a very special way, keeping track of objects, and considering some "not alive" despite existing. The Equals comparison for UnityEngine.Object is overriden to reflect this, and an existing Object might equal null:
// Both Mesh and MyObject inherit directly from UnityEngine.Object
Object plainObject = new UnityEngine.Object();
Mesh meshObject = new UnityEngine.Mesh();
MyNumber myNumber = new MyNumber(123456f);
// using the overriden Unity.Object.Equals()
print(plainObject != null); // false
print(meshObject != null); // true
print(myNumber != null); // false
// With traditional null checking, everything exists of course, as we just created them
print(plainObject as System.Object != null); // true
print(meshObject as System.Object != null); // true
print(myNumber as System.Object != null); // true
print(myNumber.number); // prints 123456, the object is there and perfectly operational
print(myNumber.name); // the program ends with a null reference exception thrown by the name set accessor, because myNumber is not "alive"
Every native Unity class that inherits from UnityEngine.Object makes any needed internal call to register the object as "alive", but this is not done in the base class itself. Basically, any attempt to create a vanilla Object, or something directly inherited from it, will be considered stillborn by the engine, and you won't get it to work as usual. If you need to create or inherit from Objects, use ScriptableObject instead, that has an explicitly special behaviour in the inner workings.

Related

My ByteBuddy generated classes can't see each other

I try to basically implement deep mocking graphs of classes (which I won't control in the wild) in order to record what is being called. The quick and dirty version using simply Mockito was surprisingly robust, but I ran into a wall trying to implement it 'properly' (and not have people ask funny questions why they need mockito in the runtime classpath).
Because this is scala, default constructors are unheard of, null values are very rarely handed gracefuly and deeply nested member classes are a norm, hence when I need to instrument a class, I need to provide actual arguments for the constructor, requiring me to instrument those in turn. Relevant snippets from my code:
private def createTracerClass(tpe :Type, clazz :Class[_]) :Class[_] = {
val name = clazz.getName + TracerClassNameSuffix + tpe.typeSymbol.fullName.replace('.', '_')
val builder =
if (clazz.isInterface) //todo: implement abstract methods!!!
ByteBuddy.subclass(clazz, new ForDefaultConstructor).name(name)
else {
val constructors = clazz.getDeclaredConstructors
.filter { c => (c.getModifiers & (PUBLIC | PROTECTED)) != 0 }.sortBy(_.getParameterCount)
if (constructors.isEmpty)
throw new PropertyReflectionException(
s"Can't instrument a tracer for class ${clazz.getName} as it has no accessible constructor."
)
val best = constructors.head
new ByteBuddy().subclass(clazz, NO_CONSTRUCTORS).name(name)
.defineConstructor(PUBLIC).intercept(
invoke(best).onSuper.`with`(best.getParameterTypes.map(createInstance):_*)
)
}
println("instrumenting " + name + "; class loader: "+clazz.getClassLoader)
val mockClass = builder
.method(not(isConstructor[MethodDescription]())).intercept(to(new MethodInterceptor()))
.defineMethod(TypeMethodName, classOf[AnyRef], PUBLIC).intercept(FixedValue.value(tpe))
.defineField(TraceFieldName, classOf[Trace], PUBLIC)
.make().load(getClassLoader, ClassLoadingStrategy.Default.WRAPPER_PERSISTENT).getLoaded
println("created class " + mockClass +"with classloader: " + mockClass.getClassLoader)
mockClass
}
private def instrumentedInstance(clazz :Class[_], modifiers :Int = PUBLIC | PROTECTED) :AnyRef =
if ((clazz.getModifiers & FINAL) != 0)
null
else {
val mockClass = MockCache.getOrElse(clazz,
clazz.synchronized {
MockCache.getOrElse(clazz, {
println("creating mock class for "+clazz.getName)
clazz.getDeclaredConstructors.filter { c => (c.getModifiers & modifiers) != 0 }
.sortBy(_.getParameterCount).headOption.map { cons =>
val subclass = ByteBuddy.subclass(clazz, NO_CONSTRUCTORS)
.name(clazz.getName + MockClassNameSuffix)
.defineConstructor(PUBLIC).intercept(
invoke(cons).onSuper.`with`(cons.getParameterTypes.map(createInstance) :_*)
).make().load(getClassLoader, ClassLoadingStrategy.Default.WRAPPER_PERSISTENT).getLoaded
MockCache.put(clazz, subclass)
subclass
}.orNull
})
}
)
println("creating a mock for " + clazz.getName + "; class loader: " + mockClass.getClassLoader)
mockClass.getConstructor().newInstance().asInstanceOf[AnyRef]
}
The issue is in the constructor generator at the bottom of the first method, which uses createInstance to create. That method in turn falls back to instrumentInstance.
The result is that I get a NoClassDefFoundError during load (LoadedTypeInitializer$ForStaticField.onLoad()) because each class is loaded with its own class loader. Unfortunately, though the reason was immediately apparent, it helped me not a bit in trying to make ByteBuddy share a class loader or somehow else make those classes available. I played with all provided arguments to make, load but to no avail; having all calls share a TypePool, different type resolution strategies - nothing except the INJECTION ClassLoaderStrategy which I don't want to use due to its reliance on private APIs which wouldn't make investing my effort into this strategical.
It seems like its a very basic issue and simple to solve, but I browsed through many code samples from other projects and I can't see anything they do differently that should make any difference. Ideas?
It's very likely related to your use of ClassLoadingStrategy.Default.WRAPPER_PERSISTENT. Using this strategy, classes are loaded in an isolated class loader that makes classes invisible to anybody not inheriting from that classes class loader.
For loading a group of classes, you'd probably want to combine all unloaded classes (.merge) and load them alltogether in a single class loader.
Note that you can also create a ByteArrayClassLoader yourself and leave it open for injection. This way later classes can be added using the injecting class loading strategy.

Spock - How to work with repeated interactions

For few test cases I'm trying to follow a DRY principle, where only the interactions are different with same test case conditions. I'm not able to find a way to implement multiple methods in the interaction { } block.
As mentioned in http://spockframework.org/spock/docs/1.3/interaction_based_testing.html#_explicit_interaction_blocks, I'm using interaction { } in the then: block like below:
Java Code:
// legacy code (still running on EJB 1.0 framework, and no dependency injection involved)
// can't alter java code base
public voidGetData() {
DataService ds = new DataService();
ds = ds.findByOffset(5);
Long len = ds.getOffset() // happy path scenario; missing a null check
// other code
}
// other varieties of same code:
public voidGetData2() {
ItemEJB tmpItem = new ItemEJB();
ItemEJB item = tmpItem.findByOffset(5);
if(null != item) {
Long len = item.getOffset();
// other code
}
}
public voidGetData3() {
ItemEJB item = new ItemEJB().findByOffset(5);
if(null != item) {
Long len = item.getOffset();
// other code
}
}
Spock Test:
def "test scene1"() {
given: "a task"
// other code ommitted
DataService mockObj = Mock(DataService)
when: "take action"
// code omitted
then: "action response"
interaction {
verifyNoDataScenario() // How to add verifyErrorScenario() interaction to the list?
}
}
private verifyDataScenario() {
1 * mockObj.findByOffset(5) >> mockObj // the findByOffset() returns an object, so mapped to same mock instance
1 * mockObj.getOffset() >> 200
}
private verifyErrorScenario() {
1 * mockObj.findByOffset(5) >> null // the findByOffset() returns null
0 * mockObj.getOffset() >> 200 // this won't be executed, and should ie expected to throw NPE
}
The interaction closure doesn't accept more than one method call. I'm not sure if it's design limitation. I believe more can be done in the closure than just mentioning the method name. I also tried interpolating the mockObj as a variable and use data pipe / data table, but since it's referring the same mock instance, it's not working. I'll post that as a separate question.
I ended up repeating the test case twice just to invoke different interaction methods. Down the line I see more scenarios, and wanted to avoid copy & paste approach. Appreciate any pointers to achieve this.
Update:
Modified shared java code as the earlier DataService name was confusing.
As there's no DI involved, and I didn't find a way to mock method variables, so I mock them using PowerMockito, e.g. PowerMockito.whenNew(DataService.class).withNoArguments().thenReturn(mockObj)
Your application code looks very strange. Is the programming style in your legacy application really that bad? First a DataService object is created with a no-arguments constructor, just to be overwritten in the next step by calling a method on that instance which again returns a DataService object. What kind of programmer creates code like that? Or did you just make up some pseudo code which does not have much in common with your real application? Please explain.
As for your test code, it also does not make sense because you instantiate DataService mockObj as a local variable in your feature method (test method), which means that in your helper method mockObj cannot be accessed. So either you need to pass the object as a parameter to the helper methods or you need to make it a field in your test class.
Last, but not least, your local mock object is never injected into the class under test because, as I said in the first paragraph, the DataService object in getData() is also a local variable. Unless your application code is compeletely fake, there is no way to inject the mock because getData() does not have any method parameter and the DataService object is not a field which could be set via setter method or constructor. Thus, you can create as many mocks as you want, the application will never have any knowledge of them. So your stubbing findByOffset(long offset) (why don't you show the code of that method?) has no effect whatsoever.
Bottom line: Please provide an example reflecting the structure of your real code, both application and test code. The snippets you provide do not make any sense, unfortunately. I am trying to help, but like this I cannot.
Update:
In my comments I mentioned refactoring your legacy code for testability by adding a constructor, setter method or an overloaded getData method with an additional parameter. Here is an example of what I mean:
Dummy helper class:
package de.scrum_master.stackoverflow.q58470315;
public class DataService {
private long offset;
public DataService(long offset) {
this.offset = offset;
}
public DataService() {}
public DataService findByOffset(long offset) {
return new DataService(offset);
}
public long getOffset() {
return offset;
}
#Override
public String toString() {
return "DataService{" +
"offset=" + offset +
'}';
}
}
Subject under test:
Let me add a private DataService member with a setter in order to make the object injectable. I am also adding a check if the ds member has been injected or not. If not, the code will behave like before in production and create a new object by itself.
package de.scrum_master.stackoverflow.q58470315;
public class ToBeTestedWithInteractions {
private DataService ds;
public void setDataService(DataService ds) {
this.ds = ds;
}
// legacy code; can't alter
public void getData() {
if (ds == null)
ds = new DataService();
ds = ds.findByOffset(5);
Long len = ds.getOffset();
}
}
Spock test:
Now let us test both the normal and the error scenario. Actually I think you should break it down into two smaller feature methods, but as you seem to wish to test everything (IMO too much) in one method, you can also do that via two distinct pairs of when-then blocks. You do not need to explicitly declare any interaction blocks in order to do so.
package de.scrum_master.stackoverflow.q58470315
import spock.lang.Specification
class RepeatedInteractionsTest extends Specification {
def "test scene1"() {
given: "subject under test with injected mock"
ToBeTestedWithInteractions subjectUnderTest = new ToBeTestedWithInteractions()
DataService dataService = Mock()
subjectUnderTest.dataService = dataService
when: "getting data"
subjectUnderTest.getData()
then: "no error, normal return values"
noExceptionThrown()
1 * dataService.findByOffset(5) >> dataService
1 * dataService.getOffset() >> 200
when: "getting data"
subjectUnderTest.getData()
then: "NPE, only first method called"
thrown NullPointerException
1 * dataService.findByOffset(5) >> null
0 * dataService.getOffset()
}
}
Please also note that testing for exceptions thrown or not thrown adds value to the test, the interaction testing just checks internal legacy code behaviour, which has little to no value.

How to create Single.just(Void)

I am writing some unit test cases for my application. I want to mock MongoClient update method, but the update returns Single<Void>.
when(mongoClient.rxUpdate(anyString(), any(JsonObject.class), any(JsonObject.class)))
.thenReturn(Single.just(Void))
Now Single.just(Void) doesn't work, what is the correct way of doing it?
--UPDATE--
So I am writing unit test for updateUserProfile method and for that I have mocked service. But the service.updateAccount method return is something I am not able to mock.
//Controller class
public void updateUserProfile(RoutingContext routingContext){
// some code
service.updateAccount(query, update)
.subscribe(r -> routingContext.response().end());
}
//Service Class
public Single<Void> updateAccount(JsonObject query, JsonObject update){
return mongoClient.rxUpdate("accounts", query, update);
}
Because the return type of mongoClient.rxUpdate is Single<Void>, I am not able to mock that part.
For now the workaround which I have figured out is:
public Single<Boolean> updateAccount(JsonObject query, JsonObject update){
return mongoClient.rxUpdate("accounts", query, update).map(_void -> true);
}
But this is just a hacky way of doing it, I want to know how can I exactly create Single<Void>
Having a method returning Single<Void> may raise some concerns, as some users have already expressed their view on this in the comments.
But if you are stuck with this and you really need to mock it (for whatever reason), there are definitely ways to create a Single<Void> instance, for example you could use the create method of the Single class:
Single<Void> singleVoid = Single.create(singleSubscriber -> {});
when(test.updateAccount(any(JsonObject.class), any(JsonObject.class))).thenReturn(singleVoid);
Single<Void> result = test.updateAccount(null, null);
result.subscribe(
aVoid -> System.out.println("incoming!") // This won't be executed.
);
Please note: you won't be able to actually emmit a Single item, since Void can't be instantiated without reflection.
A trick that could eventually work in some cases is to ommit the generic type argument and emmit an Object instead, but this could lead easily to a ClassCastException. I would not recommend to use this:
Single singleObject = Single.just(new Object());
when(test.updateAccount(any(JsonObject.class), any(JsonObject.class))).thenReturn(singleObject);
Single<Void> result = test.updateAccount(null, null);
// This is going to throw an exception:
// "java.base/java.lang.Object cannot be cast to java.base/java.lang.Void"
result.subscribe(
aVoid -> System.out.println("incoming:" + aVoid)
);
And of course you could use reflection as well (as already suggested by Minato Namikaze):
Constructor<Void> constructor = Void.class.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
Void instance = constructor.newInstance();
Single<Void> singleVoidMock = Single.just(instance);
when(test.updateAccount(any(JsonObject.class), any(JsonObject.class))).thenReturn(singleVoidMock);
Single<Void> result = test.updateAccount(null, null);
result.subscribe(
aVoid -> System.out.println("incoming:" + aVoid) // Prints: "incoming:java.lang.Void#4fb3ee4e"
);

Looking for testable design in described case

I have a system, which gets lists of objects from external system in some ABC-format, converts it to internal representation and passes to external service:
class ABCService() {
public ABCService(ExtService extService) {
this.extService = extService;
}
public void do(ABCData [] abcObjs) throws NoDataException {
if (abcObjs.length == 0) {
throw NoDataException();
} else {
List<Data> objs = new ArrayList<>();
for (ABCData abcObj : abcObjs) {
Data obj = Parser.parse(abcObj); // static call
objs.add(obj);
}
extService.do(objs);
}
}
}
When it comes to testing ABCService, we can test two things:
If no data is passed to "do", service throws an exception;
If some data is passed to "do", service should call extService and pass exactly the same number of objects, it has received from test caller.
But, though Parser factory is also tested, there is no guarantee, that output "objs" array is somehow connected to input abcObjs (e.g. method has created list with the predefined length, but method "forgets" to populate the list).
I my opinion those two test cases don't fully cover method's workflow leaving some of it dangerously untested.
How to modify ABCService design to increase it's testability?
The major testing difficulty in this code is that you have two collaborators and one of them is static.
If you can convert your Parser to a non-static (or perhaps wrap it in a non-static) and inject that as you do the extService, you could test that the parser is called the right number of times with the right arguments. Stubbing in the return values from the parser, you could also verify that your extService is called with the appropriately transformed objects instead of just the correct number of objects.
The problem you encountered is trying to handle two tasks in one function. The function do can be logically separated into two different member functions, so that you can use unittest for each of them.
By using refactoring, you can extract out the parsing and populating logic into another member function.
class ABCService() {
public void do(ABCData [] abcObjs) throws NoDataException {
extService.do(populateList(abcObjs));
}
List<Data> popuateList(ABCData[] abcObjs) {
if (abcObjs.length == 0) {
throw NoDataException();
} else {
List<Data> objs = new ArrayList<>();
for (ABCData abcObj : abcObjs) {
Data obj = Parser.parse(abcObj); // static call
objs.add(obj);
return objs;
}
}
}
while your current unittest can still remain for the "do" function, and additionally, you can add a unittest case for "populateList" function to ensure it generate correct data list

Trouble using Autofixture's CreateProxy to use Likeness, SemanticComparison features

In an earlier question I asked about Autofixture's CreateProxy method, a potential bug was identified.
I don't think this failing test is as a result of that, but rather my continued confusion about how the Likeness.Without(...).CreateProxy() syntax works. Consider the following failing test in which I make the original test ever so slightly more complex by creating a new instance of the object, considering its creation to be the SUT:
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass,
Strings = template.Brass};
// intent -> specify that .Brass should not be considered in comparison
var likeness = template.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // Ignore .Brass property
// per [https://stackoverflow.com/a/15476108/533958] explicity assign
// properties to likeness
likeness.Strings = template.Strings;
likeness.Brass = "foo"; // should be ignored
// assert: intent -> check equality between created Band & template Band
// to include all members not excluded in likeness definition
likeness.Should().Be(createdBand); // Fails
likeness.ShouldBeEquivalentTo(createdBand); // Fails
Assert.True(likeness.Equals(createdBand)); // Fails
}
Here's the Band:
public class Band
{
public string Strings { get; set; }
public string Brass { get; set; }
}
My earlier question wasn't sufficiently complex to help me understand what the Source of the Likeness should be in general.
Should the source be the output of the SUT, in which case it would be compared to the template instance created by AutoFixture?
Or should the source be the template instance created by AutoFixture, in which case it would be compared to the output of the SUT?
EDIT: Corrected an error in the test
I realized that I had incorrectly assigned the template.Brass property to both the Brass and the Strings property of the new Band instance. The updated test reflects the correction with var createdBand = new Band {Brass = template.Brass, Strings = template.Strings} and all six assertions pass now.
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass, Strings = template.Strings};
// likeness of created
var createdLikeness = createdBand.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // .Brass should not be considered in comparison
// https://stackoverflow.com/a/15476108/533958 (explicity assign properties to likeness)
createdLikeness.Strings = createdBand.Strings;
createdLikeness.Brass = "foo"; // should be ignored
// likeness of template
var templateLikeness = template.AsSource().OfLikeness<Band>()
.Without(x => x.Brass)
.CreateProxy();
templateLikeness.Strings = template.Strings;
templateLikeness.Brass = "foo";
// assert: intent -> compare created Band to template Band
createdLikeness.Should().Be(template);
createdLikeness.ShouldBeEquivalentTo(template);
Assert.True(createdLikeness.Equals(template));
templateLikeness.Should().Be(createdBand);
templateLikeness.ShouldBeEquivalentTo(createdBand);
Assert.True(templateLikeness.Equals(createdBand));
}
What you mean is:
likeness.Should().BeAssignableTo<Band>(); // Returns true.
In the example provided, the proxy generated from Likeness is a type deriving from Band, overriding Equals using the Semantic Comparison algorithm.
Using Reflection that is:
createdBand.GetType().IsAssignableFrom(likeness.GetType()) // Returns true.
Update:
The createBand and template instances are not affected by the CreateProxy method. Why they should?
With Likeness CreateProxy you basically create a Custom Equality Assertion that allows you to do:
Assert.True(likeness.Equals(createdBand)); // Passed.
Without it, the original Equality Assertion would fail:
Assert.True(template.Equals(createdBand)); // Failed.
However, the following will also fail:
Assert.True(likeness.Equals(template));
It fails because the Strings value is the one from the createdBand instance.
This behavior is expected, and you can verify it using Likeness directly:
createdBand.AsSource().OfLikeness<Band>()
.Without(x => x.Brass).ShouldEqual(template);
Output:
The provided value `Band` did not match the expected value `Band`. The following members did not match:
- Strings.