Fixture breaking after service override - dependency-injection

This test was run with PHPUnit 3.7.38 by Sebastian Bergmann on Silverstripe 3.4.0
OverrideTest.yml
ExtMember:
ext_member:
Email: ext#email.com
Password: extpassword
OverrideTest.php
class ExtMember extends Member {}
class OverrideTest extends SapphireTest
{
protected static $fixture_file = 'OverrideTest.yml';
public function testBrokenFixtures()
{
$MockExtMember = $this->getMockBuilder('ExtMember')->getMock();
$extMember = $this->objFromFixture("ExtMember", "ext_member");
Injector::inst()->registerService($MockExtMember, 'ExtMember');
$extMemberNull = $this->objFromFixture("ExtMember", "ext_member");
$this->assertEquals("ext#email.com", $extMember->Email);
$this->assertNull($extMemberNull->Email);
}
}
What happened to the $extMemberNull object? Why do all get calls return null after I register the DataObject as a service? This is a massive road block in terms of testability

When you access a property on a DataObject ($extMember->Email) it is handled by magic method __get() and results in calls of either:
$extMember->getEmail();
$extMember->getField('Email');
Since you try to use mock object without configuration, these methods return NULL

Related

Dynamic Singleton initialization (depending on parameter)

I am using dart singleton like this:
class MyHandler {
static final MyHandler _singleton = MyHandler._internal();
Database database;
factory MyHandler({bool initDb}) {
return _singleton;
}
MyHandler._internal() {
initialize();
}
void initialize() async {
// initializing database here
}
}
now my problem is, that when calling initialize on first creation in _internal() a database is instantiated. In my tests I can't access this database so I would like to only execute the initialize()-method when running my app normally but not when doing tests.
That is why I tried to pass a (bool)-parameter on the singleton creation to decide if initialize() should be called or not. Is this possible? I did not find a way to do that. Is there some other solution? Thanks!
Can it be done? Yes, but I would not recommend doing it as you have proposed. Here is an implementation for reference.
// emphasis - this is not great design
class Handler {
static final Handler _singleton = Handler._internal();
static bool _initialized = false;
factory Handler({bool initDb = true}){
if(initDb && !_initialized){
Handler._singleton._initializeDb();
Handler._initialized = true;
}
return _singleton;
}
Handler._internal();
void _initializeDb(){
// ...
}
}
What happens if a Handler is requested first with initDb = false, and then subsequently initDb = true? or vice-versa true then false? These could lead to confusing and opaque problems down the line.
There are several alternative ways to approach this problem, but utilizing dependency injection is a good approach. Once you have DI implemented, you can provide a mock Database object. Another might be connecting to a test database instead of a production one.

How to get the instance of an injected dependency, by its type using Umbraco.Core.Composing (Umbraco 8)

I need to find a way to get an instance of DataProcessingEngine without calling it's constractor.
I am trying to find a way to do so using the registered DataProcessingEngine in composition object (please see the following code). But I could not find a way to do so.
Anyone have a suggestion? Thanks in advance.
public class Composer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Register<IDataProcessingEngine, DataProcessingEngine>(Lifetime.Singleton);
//DataProcessingEngine dataProcessing = compostion.Resolve<IDataProcessingEngine>()??//no resolve function exists in Umbraco.Core.Composing
SaveImagesThread(dataProcessingEngine);
}
public Task SaveImagesThread(IDataProcessingEngine dataProcessingEngine)//TODO - decide async
{
string dataTimerTime = WebConfig.SaveProductsDataTimer;
double time = GetTimeForTimer(dataTimerTime);
if (time > 0)
{
var aTimer = new System.Timers.Timer(time);
aTimer.Elapsed += new ElapsedEventHandler(dataProcessingEngine.SaveImages);
aTimer.Start();
}
return default;
}
}
For all of you who are looking for a way to call a function (that's defined in another class in your code, an Engine or ...) from the composer(where the app starts) and want to avoid calling this function's class' constractor. I've found another way to do so:
public class QueuePollingHandler
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class SubscribeToQueuePollingHandlerComponentComposer :
ComponentComposer<SubscribeToQueuePollingHandler>
{ }
public class SubscribeToQueuePollingHandler : IComponent
{
private readonly IDataProcessingEngine _dataProcessingEngine;
public SubscribeToQueuePollingHandler(IDataProcessingEngine
dataProcessingEngine)
{
_dataProcessingEngine = dataProcessingEngine;
SaveImagesThread(_dataProcessingEngine);
}
public void SaveImagesThread(IDataProcessingEngine
dataProcessingEngine)
{
....
}
}
And the logic explenation: You create a class (SubscribeToQueuePollingHandlerComponentComposer from the example) and define its base class to be ComponentComposer<Class_that_inherits_IComponent>.
And when you start the application you could see that it gets to the registered class' constractor (SubscribeToQueuePollingHandler constructor).
That's the way that I found to be able to call a function right when the application starts without needing to call its class constractor and actualy use dependency injection.

Jenkins Shared Library Immutable Singleton

I have a Singleton patter class in my Jenkins shared library:
public class Configuration {
private static final INSTANCE = new Configuration()
static getInstance() { return INSTANCE }
private Configuration() {
}
def initialize(env, params) {
Foo = params.FOO;
}
public String Foo = ''
}
Later I can call this from elsewhere using something like this:
Configuration.instance.initialize(env, params);
config = Configuration.instance;
println 'FOO: ' + config.Foo
Ideally, I want the benefit of the Singleton pattern, but I don't want some fields to be overridden by consumers.
First Attempt:
On first thought, I would think this would work:
public class Configuration {
private static final INSTANCE = new Configuration()
static getInstance() { return INSTANCE }
private Configuration() {
}
def initialize(env, params) {
INSTANCE.#Foo = params.FOO;
}
public final String Foo = ''
}
Error:
groovy.lang.GroovyRuntimeException: Cannot set the property 'Foo' because the backing field is final.
Second Attempt:
On Second thought, I would think initializing in the constructor would work, however I don't seem to have access to params and env, unless these are passed in from the vars function, via the initialize() method.
How can I make this Singleton class immutable, or its fields read only?
I think you Could:
Define your class with "implements Serializable", as documentation advices.
Implement the constructor that would accept 1 parameter of type BaseScript, and pass this to it upon instantiation, relative to that this (which you could call internal script) you can refer to script.params, script.env, etc. and I mean you don't HAVE to use initialize, you can do all you want in the c'tor.
But wait, please tell more:
why does CI/CD code need to have a Singleton?
You're passing its data as parameters [so it's not really an immutable entity :)]
Maybe you could "simply" create an immutable map out of your parameters....
Configuration as singleton feels as if you can delegate configuration management to ... configuration management service (consul, etcd, or others).
Please elaborate, it's very curious!
Also you referred to something as "consumers". are these library consumers? or people running the jobs?
Thank you!

Groovy metaclass, mocking a service method that has throws clause

I have an abstract service:
abstract class ParentService {
abstract Map someMethod() throws NumberFormatException
}
And another service that extends above class:
class ChildService extends ParentService {
#Override
Map someMethod() throws NumberFormatException {
//Business Logic
}
}
I want to mock someMethod() using groovy metaClass. I need to mock this method for writing test cases for ChildService. This is what I have done for mocking:
ChildService.metaClass.someMethod = { -> "Mocked method" }
But this is not working and the call always executes actual method from the service. What needs to be done here? Am I missing something?
Please Note that I have to mock just one method not the entire service.
Maybe you could just mock method on instance?
def child = new ChildService()
child.metaClass.someMethod = { -> "Mocked method" }

NUnit - Mock Repository and test with dummy data

I'm trying to establish a way of unit testing my service layer (& repositories) using some dummy data. I've seen examples of this before with Generic Repositories but I'm struggling to get something working whilst using a DatabaseFactory.
When I call the GetPhrase method from repository.Object I just get null back everytime.
I'm using NUnit and Moq. Any pointers on where i'm going wrong would be appreciated, or let me know if i'm better off going down a different road
e.g. Connecting to a local db for tests (SQL CE etc)
Here are the main components of the code:
public class PhraseRepository : RepositoryBase<Phrase>, IPhraseRepository
{
public PhraseRepository(IDatabaseFactory databaseFactory)
: base(databaseFactory)
{
}
public string GetPhrase(string phraseCode)
{
return this.GetMany(p => p.PhraseCode == phraseCode).First().Descript;
}
}
public interface IPhraseRepository : IRepository<Phrase>
{
string GetPhrase(string phraseCode);
}
public class CLPRiskPhraseService : ICLPRiskPhraseService
{
private readonly IPhraseRepository phraseRepository;
public string GetPhrase(string phraseCode)
{
return phraseRepository.GetPhrase(phraseCode);
}
}
[Test]
public void GetPhrase()
{
var phrases = new FakePhraseData().GetPhrases();
phraseRepository.Setup(m => m.GetMany(It.IsAny<Expression<Func<Phrase, bool>>>())).Returns(phrases);
var result = phraseRepository.Object.GetPhrase("H300");
// Assert
NUnit.Framework.Assert.IsNotNull(phraseRepository.Object);
NUnit.Framework.Assert.AreEqual("Description0", result);
}
Invoking phraseRepository.Object.GetPhrase("H300") in your test will always return null unless you set it up to return something different.
I think you're mistakenly thinking that this call to GetPhrase will invoke GetMany like the concrete PhraseRepository does, but you need to remember that it's just a mock of the interface IPhraseRepository. A method on a mocked object will always return the default value of the return type (in this case string) unless you use Setup to change the behavior of that method.

Resources