I'm trying to write some tests for an MVC application we're developing. We have a BaseController class that contains the following:
public class BaseController : Controller
{
protected string UserRole { get; private set; }
We then have a controller that inherits from the BaseController:
public class CustomFieldController : BaseController
I've generated private accessors for both classes (just regenerated them a few minutes ago). In one of my unit tests for CustomFieldController I want to set the UserRole, so I've got the following code:
CustomFieldController controller = new CustomFieldController();
CustomFieldController_Accessor accessor = new CustomFieldController_Accessor(
new PrivateObject( controller, new PrivateType( typeof( BaseController ) ) ) );
accessor.UserRole = "OTHER";
Every time I try to run this test it throws an exception on the last line stating:
The member specified (CustomFieldEdit) could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.
As far as I can tell, I've done what it says. Not only have I recently regenerated the private accessor, but I am passing the type that defines the member into PrivateObject's constructor.
Any thoughts as to what I'm missing here? I know I can make it work by taking the "private" off the property setter, but I'd rather not do that if I can avoid it (don't want subclass implementers thinking they can inject a value into that property).
CustomFieldController controller = new CustomFieldController();
var po = new PrivateObject( controller, new PrivateType( typeof( BaseController ) ) );
CustomFieldController_Accessor accessor = new CustomFieldController_Accessor( po );
po.SetFieldOrProperty("UserRole","OTHER");
Related
According to JDBI document https://jdbi.org/#_jackson_2, it seems that it's quite straight forward to have a json property of your object model, however I've tried the following and it ran into many issues.
DB: Postgres with a column type of Jsonb
class Event {
private String name;
#Json
private EventProperty jsonProperty;
...
}
Datasource has been configured with
#Bean
public Jdbi jdbi(TransactionAwareDataSourceProxy eventStoreTxAwareDataSourceProxy) {
Jdbi jdbi = Jdbi.create(eventStoreTxAwareDataSourceProxy);
jdbi.installPlugin(new PostgresPlugin());
jdbi.installPlugin(new Jackson2Plugin());
}
SQL for binding list of insertion
INSERT INTO event (name, json_property)
VALUES (
:name,
:jsonProperty)
When running the code to insert, the following error occurred:
org.jdbi.v3.core.statement.UnableToCreateStatementException: no argument factory for type com.EventProperty [statement:"INSERT INTO event (...]
If I created EventPropertyArgumentFactory and using Jackson ObjectMapper and writeValueAsString then I can save it to DB. However, when retrieving it back from DB by
try (Handle handle = jdbi.open()) {
EventDao dao = handle.attach(EventDao.class);
return dao.findByName(name);
}
throws the following errors
java.lang.ClassCastException: Cannot cast org.postgresql.util.PGobject to com.EventProperty
I thought all I needed to do is declare the field annotated with #Json, the DB column has to be json/jsonb type and install the plugins, but seems like this is not the case?
Anyone has tried this successfully, without having to define custom row mapper and argument factory implementation?
Thanks
The documentation says:
// use #Json qualifier:
...
// also works on bean or property-mapped objects:
class MyBean {
private final MyJson property;
#Json
public MyJson getProperty() { return ...; }
}
I've checked and it's unfortunate but #Json only works when placed on a property( i.e. getter or setter) and not on a field.
You can make your work easier if you use Lombok library.
Modify lombok.config file by adding this line:
lombok.copyableannotations += org.jdbi.v3.json.Json
Now in bean declaration you can do this:
#Data // will generate setters and getters among other things
class Event {
private String name;
#Json // will be copied onto getter and setter due to config change we made
private EventProperty jsonProperty;
...
}
Have fun!
Not sure if you've figured this out by now but I just ran into this same issue and finally figured it out.
Basically, you just have to add the annotation on the getter or setter of the class, not the top-level field.
class Event {
private String name;
private EventProperty jsonProperty;
...
#Json
public getEventProperty() {
return jsonProperty;
}
}
As said in the title, I follow Model First method. So my Model classes are Automatically generated. If I want mock the DBContext derived MyModelContainer which contain DBSets of entity classes. Read some where that in order to unit test, you need to change it to IDBSet. Whether its possible to do it especially in a class that gets auto generated when I do "Run Custom Tool" is one concern. But as of now I modified it.
But the real problem is: when I try to Stub MyModelContainer to return a mock generated from IDBSet. Rhino mock is firing an InvalidOperationException: "Invalid call, the last call has been used, or no call has been made(make sure that you are calling a virtual(C#)/Overridable(VB) method."
Here is my unit test code.
MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
dbMock.Stub( x=>x.MyEntities ).Return( entityMock );
The last statement is triggering the exception. I tried using the fake implementation of IDBSet<> specified here, But no luck!
I use MVC 4, Rhino Mocks 3.6. Any help will be appreciated.
Update:
After some trials and research, I found a fix. I changed the code to:
MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
//dbMock.Stub( x=>x.MyEntities ).Return( entityMock );
dbMock.MyEntities = entityMock;
Now the InvalidOperationException is gone.
The test fails only due to ExpectationViolationException which should be normal.
As for auto generated Model class, it is found out that editing the DbContext's T4 template (.tt extension) will do the trick. Thanks to Alan's Blog
But I want to know why the previous code didn't work. Anyone?
2 reasons are possible here:
MyEntites property of MyModelContainer is not virtual.
In that case Rhino Mock can't stub this property at all. Then dbMock.Stub(x=>x.MyEntities) will fail.
MyEntites property is virtual, but has both public getter and public setter.
Then notation dbMock.Stub(x=>x.MyEntities).Return(entityMock) is not allowed. You can see explanation e.g. here.
In both cases the right fix is exactly what you did: use dbMock.MyEntities = entityMock instead of dbMock.Stub(x=>x.MyEntities).Return(entityMock).
Here is an extension method for Substituting IDbSet (with NSubstitute) to return an IQueryable
public static DbSet<T> FakeDbSet<T>(this IQueryable<T> queryable) where T : class
{
DbSet<T> fakeDbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
((IQueryable<T>)fakeDbSet).Provider.Returns(queryable.Provider);
((IQueryable<T>)fakeDbSet).Expression.Returns(queryable.Expression);
((IQueryable<T>)fakeDbSet).ElementType.Returns(queryable.ElementType);
((IQueryable<T>)fakeDbSet).GetEnumerator().Returns(queryable.GetEnumerator());
fakeDbSet.AsNoTracking().Returns(fakeDbSet);
return fakeDbSet;
}
Then you can now stub the DbContext like this:
var db = NSubstitute.Substitute.For<DataContext>();
var fakeResult = emptyCustomers.FakeDbSet();
db.Customers.Returns(fakeResult);
Here is an extension method for Stubing (with RhinoMocks) IDbSet to return an IQueryable
public static class RhinoExtensions
{
public static IDbSet<T> MockToDbSet<T>(this IQueryable<T> queryable) where T : class
{
IDbSet<T> mockDbSet = MockRepository.GenerateMock<IDbSet<T>>();
mockDbSet.Stub(m => m.Provider).Return(queryable.Provider);
mockDbSet.Stub(m => m.Expression).Return(queryable.Expression);
mockDbSet.Stub(m => m.ElementType).Return(queryable.ElementType);
mockDbSet.Stub(m => m.GetEnumerator()).Return(queryable.GetEnumerator());
return mockDbSet;
}
}
Then you can now stub the DbContext like this:
_db.Stub(p => p.Customers).Return(fakeCustomers.MockToDbSet());
I am running into the next problem. I have declared a method in the controller like the next one, to be used as a web service:
#RequestMapping(value = "/" + "prueba" , method = RequestMethod.GET)
public void prueba(ExampleBean pExample1, ExamlpleBean pExample2) {
// Wonderful code here
}
And the class ExampleBean is just, well, a Bean:
public class ExampleBean implements Serializable {
private String id;
private String whatever;
// getters, setters, and more.
}
If the interface were something like that:
#RequestMapping(value = "/" + "prueba" , method = RequestMethod.GET)
public void prueba(ExampleBean pExample1) {
// Wonderful code here
}
Each time I would like to call that web service, I would call the URL in the next way:
http://myWebProject/prueba?id=1&whatever=hola
But... How can I do when I have to give values to both params from the same class? I mean, I can not repeat parameters, so I dont know how to differ between the id from pExample1, and the id from pExample2 when writing the URL.
I mean, also with two parameters from different classes, but with an attribute with the same name. For example, if the second parameter is from the class DifferentExampleBean, which has also an "id" parameter.
Thanks a lot!
PS: I am using StringHttpMessageConverter.
What you would do is to create a parent class which would hold particular field you're interested in then both ExampleBean and ExampleBean1 would extend this parent class and you'd have only one type to be sent in prueba(ParentClass instance1, ParentClass instance2).
Where instance1 would be instance of ExampleBean and instance2 would be instance of ExampleBean2
I'm currently working on a multi-tenant application that employs Shared DB/Shared Schema approach. IOW, we enforce tenant data segregation by defining a TenantID column on all tables. By convention, all SQL reads/writes must include a Where TenantID = '?' clause. Not an ideal solution, but hindsight is 20/20.
Anyway, since virtually every page/workflow in our app must display tenant specific data, I made the (poor) decision at the project's outset to employ a Singleton to encapsulate the current user credentials (i.e. TenantID and UserID). My thinking at the time was that I didn't want to add a TenantID parameter to each and every method signature in my Data layer.
Here's what the basic pseudo-code looks like:
public class UserIdentity
{
public UserIdentity(int tenantID, int userID)
{
TenantID = tenantID;
UserID = userID;
}
public int TenantID { get; private set; }
public int UserID { get; private set; }
}
public class AuthenticationModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest +=
new EventHandler(context_AuthenticateRequest);
}
private void context_AuthenticateRequest(object sender, EventArgs e)
{
var userIdentity = _authenticationService.AuthenticateUser(sender);
if (userIdentity == null)
{
//authentication failed, so redirect to login page, etc
}
else
{
//put the userIdentity into the HttpContext object so that
//its only valid for the lifetime of a single request
HttpContext.Current.Items["UserIdentity"] = userIdentity;
}
}
}
public static class CurrentUser
{
public static UserIdentity Instance
{
get { return HttpContext.Current.Items["UserIdentity"]; }
}
}
public class WidgetRepository: IWidgetRepository{
public IEnumerable<Widget> ListWidgets(){
var tenantId = CurrentUser.Instance.TenantID;
//call sproc with tenantId parameter
}
}
As you can see, there are several code smells here. This is a singleton, so it's already not unit test friendly. On top of that you have a very tight-coupling between CurrentUser and the HttpContext object. By extension, this also means that I have a reference to System.Web in my Data layer (shudder).
I want to pay down some technical debt this sprint by getting rid of this singleton for the reasons mentioned above. I have a few thoughts on what a better implementation might be, but if anyone has any guidance or lessons learned they could share, I would be much obliged.
CurrentUser isn't quite a singleton. I'm not exactly sure what you'd call it. (A singleton by definition can only exist one at a time, and any number of UserIdentity instances can be created at will by outside code and coexist without any issues.)
Personally, i'd take CurrentUser.Instance and either move it to UserIdentity.CurrentUser, or put it together with whatever similar "get the global instance" methods and properties you have. Gets rid of the CurrentUser class, at least. While you're at it, make the property settable at the same place -- it's already settable, just in an way that (1) would look like magic if the two classes weren't shown right next to each other, and (2) makes changing how the current user identity is set later harder.
Doesn't get rid of the global, but you're not really gonna get around that without passing the UserIdentity to every function that needs it.
I created a custom RoleProvider (standard webforms, no mvc) and I would like to test it. The provider itself integrates with a custom implementation of IIdentity (with some added properties).
I have this at the moment:
var user = new Mock<IPrincipal>();
var identity = new Mock<CustomIdentity>();
user.Setup(ctx => ctx.Identity).Returns(identity.Object);
identity.SetupGet(id => id.IsAuthenticated).Returns(true);
identity.SetupGet(id => id.LoginName).Returns("test");
// IsAuthenticated is the implementation of the IIdentity interface and LoginName
However when I run this test in VS2008 then I get the following error message:
Invalid setup on a non-overridable member: id => id.IsAuthenticated
Why is this happening? And most important, what do I need to do to solve it?
Grz, Kris.
You should mock IIdentity (instead of CustomIdentity - only possible if the variables you are mocking are declared in the interface) or declare the used variables as virtual.
To mark as virtual, do this: In your concrete class CustomIdentity, use
public virtual bool isAuthenticated { get; set; }
instead of
public bool isAuthenticated { get; set; }
Moq and other free mocking frameworks doesn't let you mock members and methods of concrete class types, unless they are marked virtual.
Finally, you could create the mock yourself manually. You could inherit CustomIdentity to a test class, which would return the values as you wanted. Something like:
internal class CustomIdentityTestClass : CustomIdentity
{
public new bool isAuthenticated
{
get
{
return true;
}
}
public new string LoginName
{
get
{
return "test";
}
}
}
This class would be only used in testing, as a mock for your CustomIdentity.
--EDIT
Answer to question in comments.
Are you mocking against the interface IIdentity, or mocking against your custom type?
Without having a fuller code snippet to look at, I am guessing that it is complaining that the IsAuthenticated is not marked as virtual in your custom implementation. However, this could only be the case if you were mocking against the concrete type, not the interface.