Codeception injection fails using page object - dependency-injection

I'm new to Codeception, but I'm running into an issue injecting Page Objects. The problem occurs when I add the following construct logic to my page object.
public function __construct(\AcceptanceTester $I) {
$this->tester = $I;
}
... I got this from Login Page object example here: http://codeception.com/docs/06-ReusingTestCode#PageObjects
The error I'm getting is:
[Codeception\Exception\InjectionException]
Failed to inject dependencies in instance of 'MyCest'. Failed to create instance of 'Page\Login'. Failed to create instance of 'AcceptanceTester'. Failed to create instance of 'Codeception\Scenario'. Failed to resolve dependency 'Codeception\TestCase'.
This is how I'm injecting the page in my Cest.
protected function _inject(\Page\Login $login) {
$this->login_page = $login;
}
If I remove the __construct code, the error goes away. Is this a bug in Codeception or am I doing something wrong?
This is the work-around I found...
use \AcceptanceTester;
use Page\Login as LoginPage;
class MyCest {
protected $login_page;
public function _before(AcceptanceTester $I) {
$this->login_page = new LoginPage($I);
}
}

It is expected behaviour.
Your LoginPage constructor should not have any arguments to be instantiated during DI, so your workaround is right way to initialize LoginPage instance with AcceptanceTester instance.
When you specify AcceptanceTester as LoginPage's ctor arg DI mechanism of Codeception tries resolve dependencies recursively in the following way:
LoginPage(AcceptanceTester) -> AcceptanceTester(Scenario) -> Scenario(TestCase) -> TestCase
but TestCase is abstract class so it can not be instantiated.

Related

Jenkins | Use method from an imported java class in a groovy script

I want to be able to use a method from a Jenkins plugin via its java class
Just to point out I'm not a developer or a groovy/java expert - happy to learn!
The java class that my method is part of is com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator
From this I would like to use the method getRepoOwner()
What I've done is set my import and defined a new call to the class:
import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator
def bbSCMNav = new BitbucketSCMNavigator()
When I run this I get the error below:
org.codehaus.groovy.runtime.metaclass.MethodSelectionException: Could not find which method <init>() to invoke from this list:
public com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator#<init>(java.lang.String)
public com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator#<init>(java.lang.String, java.lang.String, java.lang.String)
I've searched for the error above Could not find which method <init>() to invoke from this list
And I came across this ticket Could not find which method <init>() to invoke from this list on newInstance in groovy closure
Can't say that I entirerly understand the reply if it's helpful to me or not as I say I'm not a developer and groovy and java are relatively new to me but happy to understand if anyone can point me in the right direction with this
The goal of this exercise is to use the method during the run-time of a build to get the output of getRepoOwner() and use that in a variable to construct a URI
This question also seems similar to mine - Calling internal methods of Jenkins plugin (thinBackup)
But I'm not using maven or a pom.xml here
Cheers
Quick Answer
This error Could not find which method < init >() is related to a missing constructor.
Almost all internal jenkins class are ready to use in groovy.
In your case, BitbucketSCMNavigator does not have a default constructor. It have a constructor with one String argument. Check this line
Explanation
I could replicate your error with another internal class org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory:
node {
stage('internal') {
org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory obj =
new org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory();
}
}
hudson.remoting.ProxyException: org.codehaus.groovy.runtime.metaclass.MethodSelectionException: Could not find which method <init>() to invoke from this list:
private org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory#<init>(org.jenkinsci.plugins.workflow.cps.CpsFlowExecution, boolean, java.lang.ClassLoader, java.util.List)
But, reviewing this class CpsFlowExecution I could see that CpsGroovyShellFactory does not have a default constructor. It have a constructor with one argument : CpsGroovyShellFactory(this)
So, If I instance the constructor with one argument, no errors appear.
node {
stage('internal') {
org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory obj =
new org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory(null);
}
}

Injecting Store to sub classes using Injector angular 7

I am injecting service from a super abstract class into our sub classes.
This works fine, except for the Store service.
What I'm doing is the following:
Super Class:
export abstract class GenericClass {
translate: TranslateService;
cdr: ChangeDetectorRef;
someService: SomeService;
otherService: OtherService;
anotherService: AnotherService;
constructor(injector: Injector){
this.translate = injector.get(TranslateService);
this.cdr = injector.get(ChangeDetectorRef);
this.someService= injector.get(SomeService);
this.otherService = injector.get(OtherService);
this.anotherService= injector.get(AnotherService);
}
}
Sub-Class (Component):
export class SubClassComponent {
constructor(injector: Injector){
super(injector);
}
}
This works fine, but with store it doesn't.
When I add Store the same way to the super class, e.g:
Super Class:
export abstract class GenericClass {
...
store: Store<AppState>;
constructor(injector: Injector){
...
this.store = injector.get(Store<AppState>);
}
}
In this case I get the following Error:
ERROR in fox-generic-form.ts(45,30): error TS2348: Value of type 'typeof Store' is not callable. Did you mean to include 'new'?
I tried this with as it suggests in the error:
this.store = injector.get(new Store<AppState>);
How ever in this case I get an error on required arguments in the constructor of Store, and after checking it does require 3 different arguments:
store.d.ts:
constructor(state$: StateObservable, actionsObserver: ActionsSubject, reducerManager: ReducerManager);
I've been searching for this for a while on the net and I can't find a solution, I did find testing scenarios, but those are not what I need for this case of components super-class & Injector.
Any one has an idea of how to use Store with Injector from a super class?
Or how I use these 3 arguments (state$: StateObservable, actionsObserver: ActionsSubject, reducerManager: ReducerManager) with Store?
Should work if you would do injector.get(Store), without the generic type.

testing if a controller method (with Guid as parameter) calls repository method (also with guid as parameter)

I'm trying to write a test method for one of my controller methods.
Here is the controller method
public ActionResult LicenseDetails(Guid id)
{
var licenseDetails = _businessUnitRepository.GetLicenseDetails(id);
return View(licenseDetails);
}
and here is the test i've written to check if it calls the method in repository.
[TestMethod]
public void ModuleDetails_Action_Calls_GetLicenseDetails()
{
_mockBusinessUnitRepository.GetLicenseDetails(Arg<Guid>.Is.Anything);
_controller.LicenseDetails(Arg<Guid>.Is.Anything);
_mockBusinessUnitRepository.AssertWasCalled(x=>x.GetLicenseDetails(Arg<Guid>.Is.Anything));
}
I'm getting error right now that says:
Test method AdminPortal.Tests.Controller_Test.Customer.BusinessUnitControllerTests.ModuleDetails_Action_Calls_GetLicenseDetails threw exception:
System.InvalidOperationException: Use Arg ONLY within a mock method call while recording. 1 arguments expected, 3 have been defined.
Ps: I'm using Rhino mock and i'm new to this testing thing
I think it is complaining about this line:
_controller.LicenseDetails(Arg<Guid>.Is.Anything);
Instead of doing that, try passing in an actual value:
_controller.LicenseDetails(Guid.NewGuid());

Testing Grails taglibs that call other taglibs

Say I've got two taglibs, Foo which does something specific for a particular part of my application, and Util which is shared across the whole thing. I want to do something like this:
class UtilTagLib {
def utilTag = { attrs ->
...
}
}
class FooTagLib {
def fooTag = {
...
out << g.utilTag(att1: "att1", att2: "att2")
...
}
}
However, when I do this, and try to run my unit test for fooTag(), I get:
groovy.lang.MissingMethodException: No signature of method: org.codehaus.groovy.grails.web.pages.GroovyPage.utilTag() is applicable for argument types: (java.util.LinkedHashMap) values: [[att1:att1, att2:att2]]
I tried giving UtilTagLib its own namespace
static namespace = "util"
and changing the call to
out << util.utilTag(...)
but this just gets me
groovy.lang.MissingPropertyException: No such property: util for class: org.example.FooTagLib
Possibly also of note: In the log, I see:
WARN - Bean named 'groovyPagesUriService' is missing.
Obviously, UtilTagLib isn't getting created and injected correctly. How can I fix this?
Solution: add the call
mockTagLib UtilTagLib
to the setUp() (or #Before) method of the test case. This is a method on GroovyPageUnitTestMixin that, somewhat counterintuitively, instantiates the specified tag library -- the real one, not a mock -- and wires it into the Grails application context. It's used internally to set up the actual taglib under test (in this case FooTagLib), but it also works to set up additional collaborator tag libs.
Note that this isn't perfect, since it makes it more of an integration test than a pure unit test -- ideally we would be using a mock UtilTagLib and just testing the interaction.
One approach would be to refactor the line:
out << g.utilTag(att1: "att1", att2: "att2")
in to its own method, say "renderUtilTag(...)", then mock that out in the unit test, e.g.:
FooTagLib.metaClass.renderUtilTag = { /* something */ }
That way you're testing the functionality of FooTagLib only in the unit test, with no dependency on UtilTagLib.

Error "More than one matching bindings are available" when using Ninject.Web.Mvc 2.0 and ASP.NET MVC 1.0

Recently I've switched to Ninject 2.0 release and started getting the following error:
Error occured: Error activating SomeController
More than one matching bindings are available.
Activation path:
1) Request for SomeController
Suggestions:
1) Ensure that you have defined a binding for SomeController only once.
However, I'm unable to find certain reproduction path. Sometimes it occurs, sometimes it does not.
I'm using NinjectHttpApplication for automatic controllers injection. Controllers are defined in separate assembly:
public class App : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
INinjectModule[] modules = new INinjectModule[] {
new MiscModule(),
new ProvidersModule(),
new RepositoryModule(),
new ServiceModule()
};
return new StandardKernel(modules);
}
protected override void OnApplicationStarted()
{
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn("Sample.Mvc");
base.OnApplicationStarted();
}
/* ............. */
}
Maybe someone is familiar with this error.
Any advice?
I finally figured this issue out recently. Apparently, the NinjectHttpApplication.RegisterAllControllersIn() function doesn't do all of the proper bindings needed. It binds your concrete controller implementations to IController requests. For example, if you have a controller class called SampleMvcController, which inherits from System.Web.Mvc.Controller. It would do the following named binding during application start:
kernel.Bind<IController>().To(SampleMvcController).InTransientScope().Named("SampleMvc");
But when debugging the NinjectControllerFactory, I find that request are being made for the Ninject Kernel to return an object for the class "SampleMvcController", not for a concrete implementation of IController, using the named binding of "SampleMvc".
Because of this, when the first web request that involves the SampleMvcController is made, it creates a binding of SampleMvcController to itself. This is not thread safe though. So if you have several web requests being made at once, the bindings can potentially happen more than once, and now you are left with this error for having multiple bindings for the SampleMvcController.
You can verify this by quickly refreshing an MVC URL, right after causing your web application to restart.
The fix:
The simplest way to fix this issue is to create a new NinjectModule for your controller bindings, and to load this module during application start. Within this module, you self bind each of your defined controllers, like so:
class ControllerModule : StandardModule {
public override Load() {
Bind<SampleMvcController>().ToSelf();
Bind<AnotherMvcController>().ToSelf();
}
}
But if you don't mind changing the Ninject source code, you can modify the RegisterAllControllersIn() function to self bind each controller it comes across.
I have been dealing with this problem for months. I tried so many options but was unable to come to a solution. I knew that it was a threading problem because it would only occur when there was a heavy load on my site. Just recently a bug was reported and fixed in the ninject source code that solves this problem.
Here is a reference to the issue. It was fixed in build 2.1.0.70 of the Ninject source. The key change was in KernelBase.cs by removing the line
context.Plan = planner.GetPlan(service);
and replacing it with
lock (planner)
{
context.Plan = planner.GetPlan(service);
}
To use this new build with MVC you will need to get the latest build of Ninject then get the latest build of ninject.web.mvc. Build ninject.web.mvc with the new Ninject build.
I have been using this new build for about a week with a heavy load and no problems. That is the longest it has gone without a problem so I would consider this to be a solution.
Are you sure you really are creating a single completely new Kernel from scratch in your OnApplicationStarted every time it's invoked ? If you're not and you're actually creating it once but potentially running the registration bit twice. Remember that you're not guaranteed to only ever have one App class instantiated ever within a given AppDomain.
My answer was a bit more obvious.
I had declared the binding for one of my controllers more than once during refactor of my code.
I added this to my global.ascx.cs file:
public void RegisterAllControllersInFix(Assembly assembly)
{
RegisterAllControllersInFix(assembly, GetControllerName);
}
public void RegisterAllControllersInFix(Assembly assembly, Func<Type, string> namingConvention)
{
foreach (Type type in assembly.GetExportedTypes().Where(IsController))
Kernel.Bind(type).ToSelf();
}
private static bool IsController(Type type)
{
return typeof(IController).IsAssignableFrom(type) && type.IsPublic && !type.IsAbstract && !type.IsInterface;
}
private static string GetControllerName(Type type)
{
string name = type.Name.ToLowerInvariant();
if (name.EndsWith("controller"))
name = name.Substring(0, name.IndexOf("controller"));
return name;
}
Then called it from my OnApplicationStarted() method as follows:
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
RegisterAllControllersInFix(Assembly.GetExecutingAssembly());
Difficult to know whether this fixed it though because it's so intermittent.

Resources