I have an api which returns an entity of type Category which has the following implementation:
class Category {
final int id;
final String title;
Category({this.id, this.title});
factory Category.fromJson(Map<String, dynamic> json) =>
Category(id: json['id'], title: json['title']);
}
I am implementing fromJson function to map the result into an object of this class.
However, the result can contain some metadata and the actual result is incapsulated into a "content" field. The implementation would be something like this:
class CategoryWrapper {
List<Category> content;
int currentPage;
int totalItems;
int totalPages;
CategoryWrapper({this.content, this.currentPage, this.totalItems, this.totalPages});
factory CategoryWrapper.fromJson(Map<String, dynamic> json) {
var list = json['content'] as List;
List<Category> objectList = list.map((i) => Category.fromJson(i)).toList();
return CategoryWrapper(content: objectList, currentPage: json['currentPage'], totalItems: json['totalItems'], totalPages: json['totalPages']);
}
}
I am implementing the fromJson function here as well to map the results into an object of this class.
What I need is to have a generic class that can take any entity (for example Category) just like I can in Java. The class would look something similar to this:
class Wrapper<T> {
List<T> content;
int currentPage;
int totalItems;
int totalPages;
Wrapper({this.content, this.currentPage, this.totalItems, this.totalPages});
factory Wrapper.fromJson(Map<String, dynamic> json) {
var list = json['content'] as List;
List<T> objectList = list.map((i) => T.fromJson(i)).toList(); // this won't work
return Wrapper(content: objectList, currentPage: json['currentPage'], totalItems: json['totalItems'], totalPages: json['totalPages']);
}
}
But this won't work because I can't call the fromJson function from a generic type.
Is there a workaround for this I can use without complicating myself with two different classes for each entity?
Related
With mockito-inline how to test static function (with stubbing other static function), or mock/stub some internal depended class?
Here is the sample:
Having a class Util which internally depending on java.security.MessageDigest
package java.security;
public abstract class MessageDigest extends MessageDigestSpi
... ...
public byte[] digest() {
byte[] result = engineDigest();
return result;
}
}
and the container class has a few static functions to be tested
public class Util {
public static byte[] getStringDigest(#NonNull String text, #NonNull String algorithm, #NonNull String charSet) {
if (text == null) {
return null;
}
MessageDigest messageDigest; //<== depend on
try {
messageDigest = MessageDigest.getInstance(algorithm);
messageDigest.update(text.getBytes(charSet));
} catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
return null;
}
return messageDigest.digest();
}
public static String generateId(#NonNull String s) {
byte[] sha1Byte = getStringDigest(s, "SHA-1", "UTF-8");
if (sha1Byte == null) {
return s;
}
// otherwise build the id
String id = buildId(sha1Byte);
return id;
}
}
would like to test the Utils.generateId(#NonNull String s) with stubbing getStringDigest() returning null, so that sometext is expected to return.
since it is static function so it was tested with powermock.
#Test
public test_util_1{
PowerMockito.mockStatic(MessageDigest.class);
String sometext = "sometext";
PowerMockito.when(Util.getStringDigest(sometext, "SHA-1", "UTF-8")).thenReturn(null);
assertEquals(sometext, Util.generateId(sometext));
}
with mock stub, when Util.getStringDigest() is called null is returned.
It worked fine.
now the mockito-inline supports testing static function (and it has problem to mix with powermockito2 when testing kotlin etc.) so the powermock is removed.
Tried with mockito-inline 3.8.0
#Test
public void test_util_1() {
String sometext = "sometext";
try (MockedStatic<Util> utilMoc = Mockito.mockStatic(Util.class)) {
utilMoc.when(() -> Util.getStringDigest(sometext, "SHA-1", "UTF-8"))
.thenReturn(null);
assertEquals(sometext, Util.generateId(sometext));
}
got error:
java.lang.AssertionError: Unexpected value
Expected :sometext
Actual :null
the Util.generateId(sometext) returns null (not the sometext).
when using assertEquals(sometext, sutilMoc.generateId(sometext)); it cannt compile and says cannt resolve the generateId().
How to use mockito-inline to test the static function?
Or if there is way to mock/stub the depended abstract class MessageDigest for stub the digest() to return null, but dont know is it possible?
found a way to make the test work (using .thenCallRealMethod()),
but still not find a way to mock the depended class which is instantiated inside the static function. if anyone knows a solution for that?
#Test
public void test_util_1() {
String sometext = "sometext";
try (MockedStatic<Util> utilMoc = Mockito.mockStatic(Util.class)) {
utilMoc.when(() -> Util.getStringDigest(anyString(), anyString(), anyString()))
.thenReturn(null);
// need to tell mock to call the original, otherwise a default mocked stub will be called
utilMoc.when(() -> Util.generateId(anyString()))
.thenCallRealMethod();
assertEquals(sometext, Util.generateId(sometext));
}
The below class is meant to be a top-layer class which brings all the benefits of nlohman::json but offers additional functions.
#include <nlohmann/json.hpp>
class Other { /* ... */ };
class AbstractData : public nlohmann::json
{
public:
AbstractData (const nlohmann::json& json) : nlohmann::json(json) { }
Other createOther(const char* key) { /* create Other class using key */ }
std::string toString() { /* convert to string */ }
/* etc. */
};
But I ran into issues when using operator[]. By default we have
AbstractData a;
auto& val = a["some_key"]; // val is nlohman::json::value_type&
and thus val loses all the extra functions.
When we provide a class function operator[]
const AbstractData& AbstractData::operator[](const char* key) const
{
return nlohmann::json::operator[](key);
}
then
AbstractData a;
auto& val = a["some_key"]; // val is AbstractData&
works as expected. But in order to achieve this, the copy constructor AbstractData (const nlohmann::json& json) is called (which is very inefficient for large objects). And this defeats the purpose of returning a reference in the first place.
I've seen questions like this one Add a method to existing C++ class in other file but they didn't offer help with my specific problem.
Any advice?
I would drop inheritance and wrap de data completely.
Why? Because the moment you need a second AbstractData, you will have to hold and potentially copy the json value. If you wrap the json data instead of using inheritance, then you can act as a view over json data.
class AbstractData {
// view over json
nlohmann::json const* _json_ptr;
auto json() -> nlohmann::json const& {
return *_json_ptr;
}
public:
AbstractData(nlohmann::json const& json) : nlohmann::json(&json) {}
Other createOther(const char* key) {
/* create Other class using key */
}
std::string toString() {}
auto operator[](const char* key) const -> AbstractData {
return AbstractData{&(json()[key])};
}
};
As you can see you can safely return by value, since your class only holds a pointer to your value and is cheap to copy.
If you also want your class to be the owner, you can store the json as a const shared pointer:
class AbstractData {
using root_t = std::shared_ptr<nlohmann::json const>;
// owner of the json root.
root_t _root;
// view over json
nlohmann::json const* _json_ptr;
auto json() -> nlohmann::json const& {
return *_json_ptr;
}
AbstractData(nlohmann::json const& json, root_t root) :
_root(root), _json_ptr(&json) {}
public:
struct new_root_t {} static constexpr new_root{};
AbstractData(new_root_t, nlohmann::json json) :
_root{std::make_shared<nlohmann::json const>(std::move(json))}, _json_ptr{_root.get()} {}
auto operator[](const char* key) const -> AbstractData {
// always pass down the root, so someone will own it
return AbstractData{json()[key], _root};
}
};
Live example
As a side note, you had undefined behaviour:
// return by reference?
const AbstractData& AbstractData::operator[](const char* key) const {
// construct a new, local value
// the local value is destroyed then returned
return nlohmann::json::operator[](key);
}
I strongly suggest to return by value here.
I'm trying to create a map of strings to functions. When it's a simple function, I've seen how to do this like so:
typedef int (*GetIntFunction)(void);
int get_temp()
{
return 42;
}
map<string, GetIntFunction> get_integer_map { { "temp", &get_temp } };
auto iter = get_integer_map.find("temp");
int val = (*iter->second()();
However, I'd like my function pointer to be to a function of a specific object. And, I know which object I need at map creation. Something like this:
class TemperatureModel
{
public:
int GetTemp();
}
TemperatureModel *tempModel = new TemperatureModel();
map<string, GetIntFunction> get_integer_map { { "temp", &(tempModel->GetTemp} };
If you'd like to know why I'm doing this, I'm trying to read a list of parameters from an input file, get their values from the correct model, and then output their values to an output file. I will also need to set values at runtime using a similar map.
The simplest approach to us old-fashioned types is to write a function:
int call_it() {
return tempModel->GetTemp();
}
and store that function in the map in the question:
map<string, GetIntFunction> get_integer_map {
{ "temp", call_it }
};
A newer approach is to use a lambda:
map<string, GetIntFunction> get_integer_map {
{ "temp", [=]() { return tempModel->GetTemp(); }
};
Another approach (as suggested in the comment by Kamil Cuk) is to use std::function to bind the object and the function:
map<string, std::function<int()>> get_integer_map {
{ "temp", std::function<int()>(&TemperatureModel::GetTemp, tempModel) }
};
Caution: code written but not compiled; it may have errors.
I have this Java test with Mockito:
public class PersistentNodeDeserializerTests {
#Test
public void userInfoPersistentNodeDeserializer() {
PersistentNode node = mock(PersistentNode.class);
when(node.stringChild("username")).thenReturn("cliff12");
//more stuff
}
}
PersistentNode is a Kotlin class:
open class PersistentNode(private val path: PersistentNodePath, val content: Any) {
val stringPath: String
get() = path.get()
val key: String
get() {
val parts = stringPath.split("/");
return parts[parts.size - 1];
}
val mapContent: Map<String, Any>
get() {
return content as HashMap<String, Any>
}
fun stringChild(child: String): String {
return mapContent.get(child) as String
}
}
I get this error:
kotlin.TypeCastException: null cannot be cast to non-null type
java.util.HashMap
How can I mock the property stringChild properly?
this library may solve your issue https://github.com/nhaarman/mockito-kotlin
EDIT: sorry, didn't realize you were using a Java test. If it's an option, try writing your test in kotlin too
I am using Microsoft Fakes framework within VS2012.
I use the following code to shim instance methods of my type.
using (ShimsContext.Create())
{
ShimDateTime.NowGet = () => { return new DateTime(1949, 10, 1); };
DateTime now = DateTime.Now; // shim works for the static property DateTime.Now.
Class1 dependency = new Class1();
using (ShimsContext.Create())
{
ShimClass1 shim1 = new ShimClass1();
StubClass1 stub1 = new StubClass1();
shim1.method1 = () => { return "shim method1"; };
shim1.IMethod1 = () => { return "shim IMethod1"; };
String s1 = dependency.method1();// shim doesn't work for the instance method.
String s2 = dependency.IMethod1();// shim doesn't work for the instance method.
}
The class1 and looks like this:
public class Class1 : Interface1
{
public String method1()
{
return "real method1";
}
//Interface 1 member
public string IMethod1()
{
return "real IMethod1";
}
}
I expect the s1 and s2 to be the shimed output, but it is still real output.
Why?
If 'method1' was static your shim would have worked. However with the current code you have not really shimmed out 'method1'. You need to either associate the instance with the shim instance
Class1 dependency = new ShimClass1() { Method1 = () => { return "Shim.Method1"; } };
or associate all instance methods with your delegate
ShimClass1.AllInstances.Method1 = (q)=> { return "Shim.Method1"; };
Also I dont see the need to have the ShimsContext.Create() done twice
If you want to use stubs to redirect IMethod1 you should be consuming the StubInterface1 instead
Class1 dependency = new StubInterface1() { Method1 = () { return ""; } };
Variations of these are available on msdn for reference