Getting rid of 'new' operators for subcomponents objects - unit-testing

I've been reading Misko Hevery's classic articles about Dependency injection, and basically 'separating the object graph creation code from the code logic'.
The main idea seems to be "get rid of the 'new' operators", put them in dedicated objects ('Factories') and inject everything you depend on."
Now, I can't seem to wrap my head about how to make this works with objects that are composed of several other components, and whose job is to isolate those components to the outerworld.
Lame example
A View class to represent a combination of a few fields, and a button. All the components depend on a graphical ui context, but you want to hide it behind the interfaces of each sub-component.
So something like (in pseudo-code, language does not really matter I guess):
class CustomView() {
public CustomView(UIContext ui) {
this.ui = ui
}
public void start() {
this.field = new Field(this.ui);
this.button = new Button(this.ui, "ClickMe");
this.button.addEventListener(function () {
if (field.getText().isEmtpy()) {
alert("Field should not be empty");
} else {
this.fireValueEntered(this.field.getText());
}
});
}
// The interface of this component is that callers
// subscribe to "addValueEnteredListener"..)
public void addValueEnteredListener(Callback ...) {
}
public void fireValueEnteredListener(text) {
// Would call each listeners in turn
}
}
The callers would do something like :
// Assuming a UIContext comes from somewhere...
ui = // Wherever you get UI Context from ?
v = new CustomView(ui);
v.addValueEnteredListener(function (text) {
// whatever...
});
Now, this code has three 'new' operators, and I'm not sure which one Misko (and other DI proponents) are advocating to rid off, or how.
Getting rid of new Field() and new Button()
Just Inject it
I don't think the idea here is to actually inject the instances of Field and Button , which could be done this way :
class CustomView() {
public CustomView(Field field, Button button) {
this.field = field;
this.button = button;
}
public void start() {
this.button.addEventListener(function () {
if (field.getText().isEmtpy()) {
alert("Field should not be empty");
} else {
this.fireValueEntered(this.field.getText());
}
});
}
// ... etc ...
This makes the code of the component lighter, surely, and it actually hides the notion of UI, so the MetaForm component has clearly been improved in terms of readability and testability.
However, the burden is now on the client to create those things :
// Assuming a UIContext comes from somewhere...
ui = // wherever ui gets injected from
form = new Form(ui);
button = new Button(ui);
v = new CustomView(form, button);
v.addValueEnteredListener(function (text) {
// whatever...
});
That sounds really troubling to me, espacially since the client know has to all the inners of the class, which sounds silly.
Mama knows, inject her instead
What the articles seems to advocate is instead injecting a Factory to create the components elements.
class CustomView() {
public CustomView(Factory factory) {
this.factory = factory;
}
public void start() {
this.field = factory.createField();
this.button = factory.createButton();
this.button.addEventListener(function () {
if (field.getText().isEmtpy()) {
alert("Field should not be empty");
} else {
this.fireValueEntered(this.field.getText());
}
});
}
// ... etc ...
And then everything gets nice for the caller, because its just has to get the factory from somewhere (and this factory will be the only to know about the UI context, so hurray for decoupling.)
// Assuming a UIContext comes from somewhere...
factory = // wherever factory gets injected from
v = new CustomView(factory);
v.addValueEnteredListener(function (text) {
// whatever...
});
A possible drawback is that when testing the MetaForm, you will typically have to use a 'Mock' Factory that ... create Mocks version of the Field & Button classes. But obviously there is another drawback ...
Yo' Factory so fat!!
How big will the Factory get ? If you follow the pattern rigorously, then every single frigging component you ever want to create in you application at runtime (wich is typically the case for UI, right) will have to get its own createXXXXX methods in at least one factory.
Because now you need :
Factory.createField to create the field
Factory.createButton to create the button
Factory.createMetaForm to create the field, the button and the MetaForm when a client (say the MetaEditPage wants to use one)
And obviously a Factory.createMetaEditPage for the client..
... and its turtles all the way.
I can see some strategies to simplify this :
As much as possible, separate the parts of the graph that are created at "startup" time from the parts that are created at runtime (using an DI framework like Spring for the former, and factories for the latter)
Layer the factories, or collocate related objects in the same factories (a UIWidgetFactory would make sense for Field and Button, but where would you put the other ones ? In a Factory linked to the Application ? To some other logical level ?)
I can almost hear all the jokes from C guys that no Java app can do anything without calling a ApplicationProcessFactoryCreator.createFactory().createProcess().startApplication() chain of nonsense...
So my questions are :
I am completely missing a point here ?
If not, which strategy would you suggest to make the things bearable ?
Addendum : why I'm not sure dependency injection would help
Assume I decide to use dependency injection, with a guice-like framework. I would end up writing code like this :
class CustomView
#Inject
private Field fiedl;
#Inject
private Button button;
public void start() {
this.button.addEventListener(....
// etc...
And then what ?
How would my "Composition Root" make use of that ? I can certainely not configure a "singleton" (with a lowercase 's', as in 'the single instance of a class) for the Field and the Button (since I want to create as many instances of them as instances of MetaForm ?
It would not make sense to use a Provider, since my problem is not which instance of buttons I want to create, but just that I want to create it lately, with some configuration (for example its text) that only makes sense for this form.
To me DI is not going to help because I am new-ing parts of my component rather than Dependencies. And I suppose I could turn any subcomponent into a dependency, and let a framework inject them. It's just that injecting subcomponents looks really artificial and couter-intuitive to me, in this case... so again, I must be missing something ;)
Edit
In particular, my issue is that I can't seem to understand how you would test the following scenario :
"when I click on the button, if the Field is empty, there should be an error".
This is doable if I inject the button, so that I can call its "fireClicked" event manually - but it feels a bit silly.
The alternative is to just do view.getButton().fireClicked() , but that looks a bit ugly...

Well, you can use some DI Framework (Spring or Guice) and get rid of factory method completely. Just put some annotation on the field/constructor/set method and DI Framework will do the work. At unit-test use mock framework.

How about not being overly obsessed with the "no new" dogma ?
My take is that DI works well for - well you know, Dependencies, or Delegates. Your example is about composition and IMHO it absolutely makes sense that the owning entity (your CustomView) creates explicitly its components. After all, the clients of the composite do not even have to know that these components exist, how they are initialized or how you use them.

Related

Reading appsettings.json directly, or accessing IOptions<T> from an Extension method

I have an extension method which is used to read a particular claim from the current ClaimsPrincipal. But I also need to check this value against a list of items which I have in the appsettings.json.
I had this working by using a ConfigurationBuilder() to read the appsettings directly in much the same way as the startup does, although instead of using
.SetBasePath(Directory.GetCurrentDirectory())
as I do in the startup, I was using
.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))
Which although isn't pretty, works fine.
However, when the Unit tests are run none of the following get me to where the appsettings are
Directory.GetCurrentDirectory()
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
and I cannot see a way of getting the IHostingEnvironment or something similar into the extension method to read out the appsettings, or indeed to ditch the ConfigurationBuilder() and get at IOptions in the extension method, in such a way that the unit test and the running code will work correctly.
I assume there must be a way of doing this? Although I expect that I should simply not be trying at all and lift the check against the list of items into another class entirely...
Putting business logic that may ever require dependencies into static methods is not recommended. This makes it difficult to inject dependencies into them. Options are few:
Redesign the static method into a service so dependencies can be injected through the constructor. (Recommended)
public class Foo : IFoo
{
private readonly IOptions<FooOptions> optionsAccessor;
public Foo(IOptions<FooOptions> optionsAccessor)
{
this.optionsAccessor = optionsAccessor ??
throw new ArgumentNullException(nameof(optionsAccessor));
}
public void DoSomething()
{
var x = this.optionsAccessor;
// Same implementation as your static method
}
}
Inject the dependencies as parameters of the extension method.
public static void DoSomething(this object o, IOptions<FooOptions> optionsAccessor)
{
// Implementation
}
Redesign the static method to be a facade over an abstract factory like this example.

React components that use context are painful to unit test

React doesn't provide an API that lets you pass in context to a created component class, so you have to write a wrapper component that provides the context.
Unfortunately, once you do this, you no longer have direct access to the component you are trying to test - unlike TestUtils.renderIntoDocument, functions like TestUtils.findRenderedComponentWithType don't return the actual rendered component instance, they only return the component constructor. Thus you can't call methods on the component, or set the component state to some known value before executing the test. The only thing you really have access to is the DOM node for your component, which is fine if all you want to do is black box testing, but for some kinds of components that's not sufficient.
I'm curious to know if anyone has come up with a solution for this. I've tried about a dozen different approaches, none of which work. (For example, I tried using 'ref' in my wrapper component, but it has the same problem - doesn't give you access to the real object.)
(Answering my own question)
Turns out the correct answer to all of this is to use enzyme, which replaces the standard React test utils - it offers a ton of features with a jQuery-like API, and best of all it completely supports component contexts. I've switched all of my tests over to it and it's great!
You can build a mock parent component like:
class MockContextContainer extends Component {
static propTypes = {
children: PropTypes.element.isRequired,
};
static childContextTypes = {
onSetTitle: PropTypes.func,
};
getChildContext() {
return {
onSetTitle: () => {},
};
}
render() {
return this.props.children;
}
}
Then use it in your test (in this case its a forgot password form example):
const cxtForgot = TestUtils.renderIntoDocument(
<MockContextContainer><ForgotPasswordForm /></MockContextContainer>
);
Which is what you may already be doing.
You can then do things like:
const input = TestUtils.findRenderedDOMComponentWithClass(
cxtForgot, 'ForgotPasswordForm-input'
);
// enter a valid email
input.value = 'abc#hotmail.com';
TestUtils.Simulate.change(input);
// no error class and button is now enabled
assert(!input.classList.contains('error'));
const button1 = TestUtils.findRenderedDOMComponentWithClass(
cxtForgot, 'primary-button'
);
assert(!button1.disabled);
the Simulate.change above can change the internal state of the component.
As for you question: "set the component state to some known value before executing the test", you can pass in different props to the component and have different tests for each scenario

Laravel Tests pass to model to View

I'm mocking my repository correctly, but in cases like show() it either returns null so the view ends up crashing the test because of calling property on null object.
I'm guessing I'm supposed to mock the eloquent model returned but I find 2 issues:
What's the point of implementing repository pattern if I'm gonna end up mocking eloquent model anyway
How do you mock them correctly? The code below gives me an error.
$this->mockRepository->shouldReceive('find')
->once()
->with(1)
->andReturn(Mockery::mock('MyNamespace\MyModel)
// The view may call $book->title, so I'm guessing I have to mock
// that call and it's returned value, but this doesn't work as it says
// 'Undefined property: Mockery\CompositeExpectation::$title'
->shouldReceive('getAttribute')
->andReturn('')
);
Edit:
I'm trying to test the controller's actions as in:
$this->call('GET', 'books/1'); // will call Controller#show(1)
The thing is, at the end of the controller, it returns a view:
$book = Repo::find(1);
return view('books.show', compact('book'));
So, the the test case also runs view method and if no $book is mocked, it is null and crashes
So you're trying to unit test your controller to make sure that the right methods are called with the expected arguments. The controller-method fetches a model from the repo and passes it to the view. So we have to make sure that
the find()-method is called on the repo
the repo returns a model
the returned model is passed to the view
But first things first:
What's the point of implementing repository pattern if I'm gonna end up mocking eloquent model anyway?
It has many purposes besides (testable) consisten data access rules through different sources, (testable) centralized cache strategies, etc. In this case, you're not testing the repository and you actually don't even care what's returned, you're just interested that certain methods are called. So in combination with the concept of dependency injection you now have a powerful tool: You can just switch the actual instance of the repo with the mock.
So let's say your controller looks like this:
class BookController extends Controller {
protected $repo;
public function __construct(MyNamespace\BookRepository $repo)
{
$this->repo = $repo;
}
public function show()
{
$book = $this->repo->find(1);
return View::make('books.show', compact('book'));
}
}
So now, within your test you just mock the repo and bind it to the container:
public function testShowBook()
{
// no need to mock this, just make sure you pass something
// to the view that is (or acts like) a book
$book = new MyNamespace\Book;
$bookRepoMock = Mockery::mock('MyNamespace\BookRepository');
// make sure the repo is queried with 1
// and you want it to return the book instanciated above
$bookRepoMock->shouldReceive('find')
->once()
->with(1)
->andReturn($book);
// bind your mock to the container, so whenever an instance of
// MyNamespace\BookRepository is needed (like in your controller),
// the mock will be loaded.
$this->app->instance('MyNamespace\BookRepository', $bookRepoMock);
// now trigger the controller method
$response = $this->call('GET', 'books/1');
$this->assertEquals(200, $response->getStatusCode());
// check if the controller passed what was returned from the repo
// to the view
$this->assertViewHas('book', $book);
}
//EDIT in response to the comment:
Now, in the first line of your testShowBook() you instantiate a new Book, which I am assuming is a subclass of Eloquent\Model. Wouldn't that invalidate the whole deal of inversion of control[...]? since if you change ORM, you'd still have to change Book so that it wouldn't be class of Model
Well... yes and no. Yes, I've instantiated the model-class in the test directly, but model in this context doesn't necessarily mean instance of Eloquent\Model but more like the model in model-view-controller. Eloquent is only the ORM and has a class named Model that you inherit from, but the model-class as itself is just an entity of the business logic. It could extend Eloquent, it could extend Doctrine, or it could extend nothing at all.
In the end it's just a class that holds the data that you pull e.g. from a database, from an architecture point of view it is not aware of any ORM, it just contains data. A Book might have an author attribute, maybe even a getAuthor() method, but it doesn't really make sense for a book to have a save() or find() method. But it does if you're using Eloquent. And it's ok, because it's convenient, and in small project there's nothing wrong with accessing it directly. But it's the repository's (or the controller's) job to deal with a specific ORM, not the model's. The actual model is sort of the outcome of an ORM-interaction.
So yes, it might be a little confusing that the model seems so tightly bound to the ORM in Laravel, but, again, it's very convenient and perfectly fine for most projects. In fact, you won't even notice it unless you're using it directly in your application code (e.g. Book::where(...)->get();) and then decide to switch from Eloquent to something like Doctrine - this would obviously break your application. But if this is all encapsulated behind a repository, the rest of your application won't even notice when you switch between databases or even ORMs.
So, you're working with repositories, so only the eloquent-implementation of the repository should actually be aware that Book also extends Eloquent\Model and that it can call a save() method on it. The point is that it doesn't (=shouldn't) matter if Book extends Model or not, it should still be instantiable anywhere in your application, because within your business logic it's just a Book, i.e. a Plain Old PHP Object with some attributes and methods describing a book and not the strategies how to find or persist the object. That's what repositories are for.
But yes, the absolute clean way is to have a BookInterface and then bind it to a specific implementation. So it could all look like this:
Interfaces:
interface BookInterface
{
/**
* Get the ISBN.
*
* #return string
*/
public function getISBN();
}
interface BookRepositoryInterface()
{
/**
* Find a book by the given Id.
*
* #return null|BookInterface
*/
public function find($id);
}
Concrete implementations:
class Book extends Model implements BookInterface
{
public function getISBN()
{
return $this->isbn;
}
}
class EloquentBookRepository implements BookRepositoryInterface
{
protected $book;
public function __construct(Model $book)
{
$this->book = $book;
}
public function find($id)
{
return $this->book->find($id);
}
}
And then bind the interfaces to the desired implementations:
App::bind('BookInterface', function()
{
return new Book;
});
App::bind('BookRepositoryInterface', function()
{
return new EloquentBookRepository(new Book);
});
It doesn't matter if Book extends Model or anything else, as long as it implements the BookInterface, it is a Book. That's why I bravely instantiated a new Book in the test. Because it doesn't matter if you change the ORM, it only matters if you have several implementations of the BookInterface, but that's not very likely (sensible?), I guess. But just to play it safe, now that it's bound to the IoC-Container, you can instantiate it like this in the test:
$book = $this->app->make('BookInterface');
which will return an instance of whatever implementation of Book you're currently using.
So, for better testability
Code to interfaces rather than concrete classes
Use Laravel's IoC-Container to bind interfaces to concrete implementations (including mocks)
Use dependency injection
I hope that makes sense.

Dll's, Message Boxes, and Unit Testing

Ok... I am working on a dll that manages some configured settings (I won't bore you with the details and reasoning here as that doesn't apply). I have a class for referencing assemblies to use to interface with this system. this class has a Load() method. When there are read or validation errors, I currently have it showing a message box. I didn't feel it should be the responsibility of the referencing assembly to manage this? Or am I wrong? Currently this is creating havoc with creating unit tests, so I'm considering adding a property to suppress messages, but still allow the exceptions to be thrown. I read on one other SO posting where someone was recommended to use IoC and a dialog result helper class. The illustration was with Constructor Injection... but that would again put that responsibility into the hands of the referencing assembly. What's best practice in this case?
Personally, I think you're wrong - sorry. The DLL's responsibility is to notify of the errors, the calling code's responsibility is to determine what to do with that notification. If it's a GUI, then it can show a dialog box. If it's a unit test, it can test appropriately. If it's a website, it can write the notification out in HTML to the user. If it's a service of some sort, it can log it. And so on.
You can use a delegate to send messages to be handled elsewhere. I have made an example below using a unittest:
public delegate void ErrorHandlingDelegate(Exception exception); //The delegate
public class AsseblymRefClass //Your class doing the business logic
{
public void DoStuff(ErrorHandlingDelegate errorHandling) //Passing the delegate as argument
{
try
{
//Do your stuff
throw new Exception();
}
catch (Exception ex)
{
errorHandling(ex); //Calling the delegate
}
}
}
//Another class that can handle the error through its method 'HandleErrorsFromOtherClass()'
public class ErrorHandlingClass
{
public void HandleErrorsFromOtherClass(Exception exception)
{
MessageBox.Show(exception.Message);
}
}
[Test]
public void testmethod() //The test that creates your class, and a class for the errorhandling, and connects the two
{
ErrorHandlingClass errorHandling = new ErrorHandlingClass();
AsseblymRefClass assemblyRef = new AsseblymRefClass();
assemblyRef.DoStuff(errorHandling.HandleErrorsFromOtherClass);
}
Any method that fits the delegate can be used. Thus, you can replace your production code, with something that doesn't show a messagebox when unit testing.

Optional dependency injection for unit testing

I'm considering my options for setting up a class for unit testing. This particular class should ALWAYS use the same soap client configuration under normal circumstances. I feel like users of the class shouldn't need to be concerned with setting up a soap client when they use it. Or, even be aware that it uses soap at all.
Really the only exception is in unit testing. I'll need to be able to mock the Soap_Client. I've come up with the following approach where i create the soap client in the constructor and can optionally set it with setSoapClient().
class WebServiceLayer
{
const WSDL_URL = 'https://www.example.com/?WSDL';
private $soapClient;
public function __construct()
{
$this->soapClient = new Soap_Client(self::WSDL_URL);
}
public function setSoapClient(Soap_Client $soapClient)
{
$this->soapClient = $soapClient;
}
public function fetchSomeResponse()
{
$soapClient = $this->soapClient;
return $soapClient->someRequest();
}
}
Is this a valid way to handle this? The only problem i see with it, is that im instantiating the client in the constructor which "i've heard" is something to avoid.
I've run into this dilemma before on other classes, so it would be really nice to get peoples opinions on this.
Looks fine to me... you're using standard Setter injection. The only strange thing is returning a new client in the Getter. Why not return null if it hasn't been injected?