Example: I have repository A inside __construct(repo B, repo C) and I want make unit test for function inside repo A but inside it has call b->func_b1 and C->func_c1, how to make? thank you so much!
#Repo A
public function __construct(
CandidateStepMasterInterface $stepMasterRepo,
CandidateProcessInterface $processRepo,
CandidateInterface $candidateRepo
) {
parent::__construct();
$this->stepMasterRepo = $stepMasterRepo;
$this->processRepo = $processRepo;
$this->candidateRepo = $candidateRepo;
}
I make unit test for func here
public function funcA($itemExample) {
//code here
$processes = $this->stepMasterRepo->func_b1();
$dataProcess = $this->processRepo->func_c1($itemExample);
$result = $this->candidateRepo->func_d1($itemExample);
// code here
return $result
}
Unit test file
protected function setUp(): void
{
$this->stepMasterRepo = m::mock(CandidateStepMasterInterface::class)->makePartial();
$this->processRepo = m::mock(CandidateProcessInterface::class)->makePartial();
$this->candidateRepo = m::mock(CandidateInterface::class)->makePartial();
$this->candidatePhaseMasterMock = m::mock(CandidatePhaseMasterRepository::class)->makePartial();
$this->candidatePhaseMasterRepo = new CandidatePhaseMasterRepository(
$this->stepMasterRepo,
$this->processRepo,
$this->candidateRepo,
);
parent::setUp(); // TODO: Change the autogenerated stub
}
public function test_funcA() {
$dataExample = [];
$result = $this->candidatePhaseMasterRepo->funcA(1);
$this->assertEquals($dataExample, $result);
}
Run unit test:::
Mockery\Exception\BadMethodCallException: Received Mockery_0_App_Repositories_SaltCrm_Interfaces_CandidateStepMasterInterface::func_b1(), but no expectations were specified
Related
Let say we have an object:
#:checkDirty
class Test {
var a:Int;
var b(default, default):String;
var c(get, set):Array<Int>;
public function new() {
...
}
public function get_c() {
...
}
public function set_c(n) {
...
}
}
Could we write a macro checkDirty so that any change to field/properties would set property dirty to true. Macro would generate dirty field as Bool and clearDirty function to set it to false.
var test = new Test();
trace(test.dirty); // false
test.a = 12;
trace(test.dirty); // true
test.clearDirty();
trace(test.dirty); //false
test.b = "test"
trace(test.dirty); //true
test.clearDirty();
test.c = [1,2,3];
trace(test.dirty); //true
Just to note - whenever you consider proxying access to an object, in my experience, there are always hidden costs / added complexity. :)
That said, you have a few approaches:
First, if you want it to be pure Haxe, then either a macro or an abstract can get the job done. Either way, you're effectively transforming every property access into a function call that sets the value and also sets dirty.
For example, an abstract using the #:resolve getter and setter can be found in the NME source code, replicated here for convenience:
#:forward(decode,toString)
abstract URLVariables(URLVariablesBase)
{
public function new(?inEncoded:String)
{
this = new URLVariablesBase(inEncoded);
}
#:resolve
public function set(name:String, value:String) : String
{
return this.set(name,value);
}
#:resolve
public function get(name:String):String
{
return this.get(name);
}
}
This may be an older syntax, I'm not sure... also look at the operator overloading examples on the Haxe manual:
#:op(a.b) public function fieldRead(name:String)
return this.indexOf(name);
#:op(a.b) public function fieldWrite(name:String, value:String)
return this.split(name).join(value);
Second, I'd just point out that if the underlying language / runtime supports some kind of Proxy object (e.g. JavaScript Proxy), and macro / abstract isn't working as expected, then you could build your functionality on top of that.
I wrote a post (archive) about doing this kind of thing (except for emitting events) before - you can use a #:build macro to modify class members, be it appending an extra assignment into setter or replacing the field with a property.
So a modified version might look like so:
class Macro {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields.copy()) { // (copy fields so that we don't go over freshly added ones)
switch (field.kind) {
case FVar(fieldType, fieldExpr), FProp("default", "default", fieldType, fieldExpr):
var fieldName = field.name;
if (fieldName == "dirty") continue;
var setterName = "set_" + fieldName;
var tmp_class = macro class {
public var $fieldName(default, set):$fieldType = $fieldExpr;
public function $setterName(v:$fieldType):$fieldType {
$i{fieldName} = v;
this.dirty = true;
return v;
}
};
for (mcf in tmp_class.fields) fields.push(mcf);
fields.remove(field);
case FProp(_, "set", t, e):
var setter = Lambda.find(fields, (f) -> f.name == "set_" + field.name);
if (setter == null) continue;
switch (setter.kind) {
case FFun(f):
f.expr = macro { dirty = true; ${f.expr}; };
default:
}
default:
}
}
if (Lambda.find(fields, (f) -> f.name == "dirty") == null) fields.push((macro class {
public var dirty:Bool = false;
}).fields[0]);
return fields;
}
}
which, if used as
#:build(Macro.build())
#:keep class Some {
public function new() {}
public var one:Int;
public var two(default, set):String;
function set_two(v:String):String {
two = v;
return v;
}
}
Would emit the following JS:
var Some = function() {
this.dirty = false;
};
Some.prototype = {
set_two: function(v) {
this.dirty = true;
this.two = v;
return v;
}
,set_one: function(v) {
this.one = v;
this.dirty = true;
return v;
}
};
I have a data provider that has an Observable<Int> as part of the public API. My class under test maps this into a Observable<String>.
How do I create a mock so that it can send out different values on the data provider's observable?
I can do it using a Fake object, but that is a lot of work that I don't think is necessary with MockK.
Simplified code:
interface DataProvider {
val numberData:Observable<Int>
}
class FakeDataProvider():DataProvider {
private val _numberData = BehaviorSubject.createDefault(0)
override val numberData = _numberData.hide()
// Note: the internals of this class cause the _numberData changes.
// I can use this method to fake the changes for this fake object,
// but the real class doesn't have this method.
fun fakeNewNumber( newNumber:Int ) {
_numberData.onNext( newNumber )
}
}
interface ClassUnderTest {
val stringData:Observable<String>
}
class MyClassUnderTest( dataProvider: DataProvider ):ClassUnderTest {
override val stringData = dataProvider.numberData.map { "string = " + it.toString() }
}
class MockKTests {
#Test fun testUsingFakeDataProvider() {
val fakeDataProvider = FakeDataProvider()
val classUnderTest = MyClassUnderTest( fakeDataProvider )
val stringDataTestObserver = TestObserver<String>()
classUnderTest.stringData.subscribe( stringDataTestObserver )
fakeDataProvider.fakeNewNumber( 1 )
fakeDataProvider.fakeNewNumber( 2 )
fakeDataProvider.fakeNewNumber( 3 )
// Note we are expecting the initial value of 0 to also come through
stringDataTestObserver.assertValuesOnly( "string = 0", "string = 1","string = 2","string = 3" )
}
// How do you write the mock to trigger the dataProvider observable?
#Test fun testUsingMockDataProvider() {
val mockDataProvider = mockk<DataProvider>()
// every { ... what goes here ... } just Runs
val classUnderTest = MyClassUnderTest( mockDataProvider )
val stringDataTestObserver = TestObserver<String>()
classUnderTest.stringData.subscribe( stringDataTestObserver )
// Note we are expecting the initial value of 0 to also come through
stringDataTestObserver.assertValuesOnly( "string = 0", "string = 1","string = 2","string = 3" )
}
}
Try to use following:
every { mockDataProvider.numberData } answers { Observable.range(1, 3) }
And maybe you need to use another way to make a mock object, like this:
val mockDataProvider = spyk(DataProvider())
Do something like this where we create an observable fakelist of the observable
var fakeList :List<Quiz> = (listOf<Quiz>(
Quiz("G1","fromtest","","",1)
))
var observableFakelist = Observable.fromArray(fakeList)
you can then return your observableFakelist.
I need to know, what would be proper way to implement Maps with 64 bit keys. There will not be so many items in them, I just need to use various bits of the key for various things with large enough address space and I need it to be very fast, so String keys would probably be too slow. So far I tried:
import haxe.Int64;
import haxe.Unserializer;
import haxe.Serializer;
class Test {
static function main () {
var key:Int64 = 1 << 63 | 0x00000001;
var omap:Map<Int64, String> = new Map<Int64, String>();
omap.set(key, "test");
var smap:Map<Int64, String> = Unserializer.run(Serializer.run(omap));
var key2:Int64 = 1 << 63 | 0x00000001;
trace(key+" "+smap.get(key2));
}
}
http://try.haxe.org/#7CDb2
which obviously doesn't work, because haxe.Int64 creates an object instance. Using cpp.Int64 works, because it for some reason falls back to 32 bit integer in my cpp code and I don't know what am I doing wrong. How can I force it to "stay" 64 bit, or should I do it some other way?
EDIT: This is currently not working on native targets due to bug / current implementation in hxcpp: https://github.com/HaxeFoundation/hxcpp/issues/523
I figured out this workaround / wrapper, which may not be the most efficient solution possible, but it seems to work.
import haxe.Int64;
import haxe.Unserializer;
import haxe.Serializer;
class Test {
static function main () {
var key:Int64 = Int64.make(1000,1);
var omap:Int64Map<String> = new Int64Map();
omap.set(key, "test");
var smap:Int64Map<String> = Unserializer.run(Serializer.run(omap));
var key2:Int64 = Int64.make(1000,1);
trace(key+" "+smap.get(key2));
}
}
class Int64Map<V> {
private var map:Map<Int64,V>;
public function new() : Void {
this.map = new Map<Int64,V>();
}
public function set(key:Int64, value:V):Void {
this.map.set(key, value);
}
public inline function get(key:Int64):Null<V> {
var skey:Null<Int64> = getMapKey(key);
if (skey != null) return this.map.get(skey);
return null;
}
public inline function exists(key:Int64):Bool {
return (getMapKey(key) != null);
}
public function remove( key : Int64 ) : Bool {
var skey:Null<Int64> = getMapKey(key);
if (skey != null) return this.map.remove(skey);
return false;
}
public function keys() : Iterator<Int64> {
return this.map.keys();
}
public function toString() : String {
return this.map.toString();
}
public function iterator() : Iterator<V> {
return this.map.iterator();
}
private function getMapKey(key:Int64):Null<Int64> {
for (ikey in this.map.keys()){
if (Int64.eq(key, ikey)){
return ikey;
}
}
return null;
}
}
http://try.haxe.org/#57686
I want to test the following class:
public class DBSync {
public dbNotify( String path ) {
if (!path) {
return
}
def pathIndex = path.lastIndexOf(File.separator)
if (pathIndex > 0) {
def folder = path[0..pathIndex - 1]
def fileName = path[pathIndex + 1..path.length() - 1]
println "Syncing from directory $folder for filename $fileName"
if (fileName.contains(EXCLUDE_FILE_PATTERN)) {
println "Filename is $EXCLUDE_FILE_PATTERN skipping db write "
return
}
writeToDB(folder, fileName)
}
}
public writeToDB ( folder, file ) {
// inserting to database
}
}
The test class is:
public class TestDBSync {
#Test
public void test() {
def dbSyncContext = new MockFor(DBSync)
def file = "file.zip"
def folder = "data"
def path = folder + File.separator + file
def called = false
// Expect at least one call
mockDBSyncContext.demand.writeToDB(1..1) { String folderargs, String fileargs -> called = true }
mockDBSyncContext.demand.dbNodify(1..1) { String pathargs -> return }
// Obtaining a usuable mock instance
def mockDBSyncProxy = mockDBSyncContext.proxyInstance()
// Fake calling the method
mockDBSyncContext.use {
mockDBSyncProxy.dbNotify(path )
}
// Verify invoked at least once?
mockDBSyncContext.verify(mockDBSyncProxy)
}
}
The test is failing and I am getting the following error:
junit.framework.AssertionFailedError: No call to 'dbNotify' expected
at this point. Still 1 call(s) to 'writeToDB' expected.
I have a case where I need to call several different web endpoints and need to do the same setup and tear down for every call. I am trying to write a more generic method where I can pass in the method I want to execute along with the package to send to the endpoint and expect a string return.
From my code I can make this call:
var ret = WebServiceHandler.Execute(WebServiceHandler.LoadNewAsset(package));
The definition of Execute looks like:
internal static string Execute<T>(Func<T, string> executeThisAction)
{
Func<T, string> resp;
Setup();
resp = executeThisAction;
CleanUp();
return resp.ToString();
}
This is one of the methods I want to execute:
internal static Func<CarsWS_AssetLoad, string> LoadNewAsset(AssetLoad package)
{
string resp;
try
{
// Make the web service call...
var assetLoadReturn = _service.LoadNewAsset(new LoadNewAssetRequest {UserCredentialsHeader = _credentials, asset = package});
// Evaluate results...
if (assetLoadReturn.LoadNewAssetResult.responseType == "Success")
resp = (result != null && !String.IsNullOrEmpty(result.asset.assetID))
? "Got assetID: " + result.asset.assetID
: "No assetID returned.";
else
resp = result.responseDescription.Trim();
}
catch (Exception ex)
{
resp = "Error calling LoadNewAsset()." + Environment.NewLine + ex.GetFullMessage();
}
return resp; // <== THIS IS NOT A VALID RETURN <== //
}
My brain is shutting off at this point. How do I return the string back up the call stack correctly???
I assume that in your LoadNewAsset method the CarsWS_AssetLoad class is actually the same as AssetLoad and it was just a editing issue with your question.
That being the case, I think this is what you want:
internal static string Execute<T>(Func<T, string> executeThisAction, AssetLoad package)
{
string resp;
Setup();
resp = executeThisAction(package);
CleanUp();
return resp;
}
internal static Func<AssetLoad, string> LoadNewAsset()
{
return package =>
{
string resp;
var assetLoadReturn = _service.LoadNewAsset(new LoadNewAssetRequest {UserCredentialsHeader = _credentials, asset = package});
if (assetLoadReturn.LoadNewAssetResult.responseType == "Success")
resp = (result != null && !String.IsNullOrEmpty(result.asset.assetID))
? "Got assetID: " + result.asset.assetID
: "No assetID returned.";
else
resp = result.responseDescription.Trim();
return resp;
};
}
The use of the variable result in the LoadNewAsset is a little confusing too. Did you mean to use LoadNewAsset instead?
The above code should be able to workable for you, but it's really not the right way to go about coding this.
I assume that the Setup & CleanUp code is all about instantiating the _service that you're calling?
So the key is to code it this way:
internal static string Execute<T>(Func<IAssetService, T, string> serviceCall, AssetLoad package)
{
string resp;
var service = Setup();
resp = serviceCall(service, package);
CleanUp(service);
return resp;
}
internal static Func<IAssetService, AssetLoad, string> GetLoadNewAssetFunc()
{
return (service, package) =>
{
string resp;
var assetLoadReturn = service.LoadNewAsset(new LoadNewAssetRequest {UserCredentialsHeader = _credentials, asset = package});
if (assetLoadReturn.LoadNewAssetResult.responseType == "Success")
resp = (result != null && !String.IsNullOrEmpty(result.asset.assetID))
? "Got assetID: " + result.asset.assetID
: "No assetID returned.";
else
resp = result.responseDescription.Trim();
return resp;
};
}
Ideally if you would bring the Setup & CleanUp code into the Execute method so that the only way to call the set-up and clean-up code is thru the Execute method.
Even better, if the service class implements IDisposable then your execute code would look like this:
internal static string Execute<T>(Func<IAssetService, T, string> serviceCall, AssetLoad package)
{
using (var service = Setup())
{
return serviceCall(service, package);
}
}
Let me know if I've missed anything.
Replace:
internal static string Execute<T>(Func<T, string> executeThisAction)
with
internal static string Execute<T>(Func<T, string> executeThisAction, T argument)
then replace:
internal static Func<CarsWS_AssetLoad, string> LoadNewAsset(AssetLoad package)
with
internal static string LoadNewAsset(AssetLoad package)
then to call it:
var ret = WebServiceHandler.Execute(WebServiceHandler.LoadNewAsset, package);