1

I need to prepare my database for unit testing and hence in the set up method I want to get rid of the data.

However, I don't want to be anybody else but the unit test dll to be able to call into my DeleteAllData() method in my Data Access Layer. What can be done?

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
dexter
  • 7,063
  • 9
  • 54
  • 71

5 Answers5

3

While others already suggested how to restrict code making calls to your method, they do not create a security boundary and can be spoofed (unless you sign both assemblies and verify the evidence).

Having a method in your business logic called DeleteAllData sounds pretty scary to me. If this method is only used from a unit test, I would probably move it to the unit test assembly. If that is not possible, I would at least put the code in a compiler directive to only compile in debug mode.

MvdD
  • 22,082
  • 8
  • 65
  • 93
  • nice, i will certainly do! – dexter Jan 12 '15 at 17:02
  • "they do not create a security boundary and can be spoofed (unless you sign both assemblies and verify the evidence)." > that's why using `InternalsVisibleTo` needs a signed assembly name to work. So it *is* validated and can't be spoofed that easy. You need a breach in the certificate authority to break this. – Patrick Hofman Jan 12 '15 at 21:25
  • @PatrickHofman InternalsVisibleTo works just fine with delay signed assemblies which are not really signed. – MvdD Jan 13 '15 at 00:47
1

You can sign both your assemblies, and then use the InternalsVisibleTo attribute to make the unit test assembly the only one able to see the internals. You need to make all methods, properties and classes internal that you only want to expose to the unit test project.

MSDN on the InternalsVisibleToAttribute:

Specifies that types that are ordinarily visible only within the current assembly are visible to a specified assembly.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • 2
    @dexter: Misread your question initially. Patrick's answer is correct when you need to reference internals in one assembly from another, such as a unit test assembly. I left my answer because he implies using `internal`, but doesn't say so explicitly. – Chris Pratt Jan 12 '15 at 15:42
  • @PatrickHofman I want to believe there is gotta be another way to do this except for relying on the .net framework to do the checks using the attribute. Some kinda factory pattern with modifications for checking the caller in the callee? But maybe what you are proposing is the best way I am just contemplating. – dexter Jan 12 '15 at 15:45
  • Why not relying on the framework? Do you think you can do better? I have no idea how to do it different... – Patrick Hofman Jan 12 '15 at 15:54
  • 1
    @dexter: You can always hack in the IL and get the method out. No way to prevent that. – Patrick Hofman Jan 12 '15 at 16:02
  • @PatrickHofman, how about this type of hack: make the method private and use reflection in the test assembly to invoke it. – dexter Jan 12 '15 at 16:59
  • 1
    That is still the same... The documented way is better. Let .Net check the evidence. – Patrick Hofman Jan 12 '15 at 17:33
1

you could probably use a combination of Assembly.GetCallingAssembly() and interrogation of the call stack in your DeleteAllData() method to ensure that your method is only being called by the method you expect.

You might need to prevent the jitter inlining your method calls to ensure that the calling assembly method and call stack are preserved when they get to your DeleteAllData() method.

The call stack might be enough, but the calling assembly might also be needed.

I've not tried this but think it should work in theory.

Community
  • 1
  • 1
Sam Holder
  • 32,535
  • 13
  • 101
  • 181
0

Mark it with the internal keyword. From the MSDN docs:

The internal keyword is an access modifier for types and type members. Internal types or members are accessible only within files in the same assembly

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • @Chris Pratt - this would have worked if my code just belonged to one assembly. However, my Data Access code with contenxt.Delete is in its own assembly, versus the client for the call in question is in the other. – dexter Jan 12 '15 at 15:42
0

I have one more approach to achieve thing mentioned in the question.

If you are using VSTS unit test.

Make the method as private in class so that other classes and assemblies can not access that.

Now to invoke that private method from Unit test use PrivateObject

Here is Microsoft documentation of the PrivateObject :- link

How to use Private Object :- link

Jenish Rabadiya
  • 6,708
  • 6
  • 33
  • 62