dart-lang / test

A library for writing unit tests in Dart.
https://pub.dev/packages/test
490 stars 213 forks source link

Incorrect invocation of noSuchMethod() for getters in mock objects while unittesting #215

Closed DartBot closed 9 years ago

DartBot commented 9 years ago

Originally opened as dart-lang/sdk#10524

This issue was originally filed by iza...@gmail.com


I'm doing some unit testing with one of my libs and I'm getting what I think is an incorrect invocation of noSuchMethod() where a property is not treated like a getter and its name has a trailing "@0x210e5be6".

I have the following class:

  class ObjectoryDaoImplementation extends DaoImplementation {     Objectory _db;     ObjectoryDaoImplementation([this._db]) {       .       .       .   }

And in my unit tests I mock it with:

  class MockObjectoryDaoImplementation extends Mock implements ObjectoryDaoImplementation {}

Then I program the mock to return a mock _db with this:

  MockObjectoryDaoImplementation daoImpl = new MockObjectoryDaoImplementation();   MockObjectory db = new MockObjectory();   daoImpl.when(callsTo("get _db")).alwaysReturn(db);

It's important to note that due to the fact that the mock implements ObjectoryDaoImplementation, but does not extend it, it has no real _db property. The thing is that, when I call _db on the mock, it jumps to noSuchMethod() but the member name in the Invocation argument is "_db@0x210e5b6e" instead of "_db"

I suppose the correct behavior would be that "_db@0x210e5b6e" is not passed, but just a plain "_db", but I'm not sure if this is correct. Is this a bug of mirrors, of unit test, or a gap in the language spec?

DartBot commented 9 years ago

Comment by lrhn


What you are seeing here is the library-localized version of a library private name. Since "_db" has different meanings in different libraries, the VM puts a library unique suffix on all private variables.

I think it's just that the Mock doesn't really work with private names. If it did work, you would still need a way to recognize which "_db" name was used, and only match the ones from the correct library.

DartBot commented 9 years ago

This comment was originally written by iz...@gmail.com


But... Isn't properties supposed to be like getters? I mean, if I implement some class with some declared property it should act as if it had a getter and a setter. In fact it does in normal code, but not in mirrored code.

See this article (classes Language and LanguageImpl) for typing a JSON object. It uses the same technique:

http://www.dartlang.org/articles/json-web-service/#introducing-jsonobject

DartBot commented 9 years ago

Comment by lrhn


Properties/fields are getters (or rather: A field is a cell on the object where a value can be stored, together with a getter and setter accessing the cell)

The problem here is that the name of the field is private, and you are trying to access it, potentially from outside the library that the private name is private to. That means that you can't really specify what name to match against, because writing "_db" in another library really means specifying a different name.

Well, actually, I don't think the Mock library would work inside the library either - it just doesn't seem to handle private names at all, which is kind of understandable. If it were to work, it should be using Symbols instead of strings, so you could specify the private name of a specific library.

That said, the VM should not expose its internal name mangling. That's just going to make people depend on it, and it's really an internal detail, and dart2js code will be different.

DartBot commented 9 years ago

This comment was originally written by izaera...@gmail.com


For the sake of documenting this bug:

-All my code is inside the same library because I'm putting the tests in the same library as the code. -Obviously, Mock is not in my library, so technically its noSuchMethod error is in other library.

Anyway, I would like this setup to work if it is possible. I don't see too much sense in having to cope with internal cross-library issues when mocking and testing and, IMHO, the setup I have placed would make sense to everyone who reads it.

Also, I agree that exposing something like @­0xwhatever as a field name does not make any sense. It cannot be used by anybody and can only cause problems.

DartBot commented 9 years ago

Comment by lrhn


I think this should be counted as a bug against the Mock code's way of handling private names. I'm not sure it can work at all using a string based interface, and not Symbols, but only time can tell.


Added Area-UnitTest, Triaged labels.

DartBot commented 9 years ago

Comment by a14n


see also issue dart-lang/sdk#9285

DartBot commented 9 years ago

Comment by gramster


Added Duplicate label. Marked as being merged into dart-lang/sdk#9285.

DartBot commented 9 years ago

Comment by kevmoo


Added Pkg-Unittest label.

DartBot commented 9 years ago

Comment by kevmoo


Removed Area-UnitTest label. Added Area-Pkg label.