Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#5 automated tests #121

Merged
merged 13 commits into from
Jan 20, 2021
Merged

#5 automated tests #121

merged 13 commits into from
Jan 20, 2021

Conversation

timyhac
Copy link
Collaborator

@timyhac timyhac commented Jan 15, 2021

Hey there @jkoplo - was hoping to get your opinion on how these tests are structured.

In order to set up the test harness I need to remove the direct dependency of Tag on the native plctag methods, so I created INativeTag and added an indirection layer to the native library.

Main thing that I'm not sure about is that I needed to remove the sealed keyword from Tag - I'm not totally clear on why that was there. To be able to mock the dependency on the native library, I added a private constructor to allow dependency injection of an INativeTag implementation (i.e. a mock) but keeping that constructor invisible from the public API for Tag.

* Added an indirection layer for accessing native methods.
* Make mocking accessible only to the libplctag.Tests friend assembly
This means that even if the Tag wasn't initialized, it is still unusable after disposal. Properly reflects disposal semantics. Somewhat related to Issue #99
@timyhac
Copy link
Collaborator Author

timyhac commented Jan 16, 2021

Actually, I've updated this slightly so now we have a few layers of indirection.

The end result:

  • The real logic has been moved to an internal class NativeTagWrapper.
  • The public Tag class is sealed.
  • NativeTagWrapper is exposed to the test project and the NativeTag interface can be mocked.

One thing I noted was that Tag<M,T> isn't sealed, but Tag is - I'm not super clear on why that is.

@jkoplo
Copy link
Member

jkoplo commented Jan 17, 2021

I'll try to take a look this weekend. Real life has been getting in the way, but I'd like to get back into this project some more...

@timyhac
Copy link
Collaborator Author

timyhac commented Jan 18, 2021

@jkoplo - I'm thinking it may be useful if I merge this work but do not publish anything to nuget until we've both agreed on testing approach. Are you ok with that?

Update: not so much the testing approach, I don't think we have many options besides what has been done here, but more in terms of what the public API should be after integrating this.

Copy link
Member

@jkoplo jkoplo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so it looks like everything that was in Tag became NativeTagWrapper' (all the additional code that was provided beyond the native libplctag). And the new Tagis just a thin re-implementation ofNativeTagWrapper` that injects 'NativeTag' by default.

And then a NativeTag was created that's one-for-one with libplctag and implements the new INativeTag.

This allows us to test NativeTagWrapper but still keep Tag simple for library users. I think I follow...

@jkoplo
Copy link
Member

jkoplo commented Jan 19, 2021

Thinking through this more, here's our layers from highest-level to lowest-level:

  1. TagOfT (Really Tag<M, T>) - Object that has a nice clean surface and allows for native object types.
  2. Tag - Still user-facing, but a lower level way to use tags.
  3. NativeTagWrapper - Internal. Responsible for enforcing order of operations with some .NET friendly handling.
  4. NativeTag - Internal. Exists just to make libplctag.NativeImport.plctag injectable against INativeTag.
  5. libplctag.NativeImport.plctag - Wraps the C DLL into .NET calls.

Could you simplify this by making INativeTag part of libplctag.NativeImport and removing NativeTag? Or does that play havoc with dependencies and access levels?

On the unit-test side of things, it looks pretty good. I'll be honest that I only have an academic understanding of unit testing. Other than using and modifying other people's tests on a few open-source projects, I've never written them from scratch for my own code.

@timyhac
Copy link
Collaborator Author

timyhac commented Jan 19, 2021

"Or does that play havoc with dependencies and access levels?" - yes, we would need to expose INativeTag and NativeTag in NativeImport for that to work - it would mean that the test project would (directly) depend on the NativeImport library.

Static methods can't be used to implement an interface, so we would still need the NativeTag type, it would just be moved to NativeImport.

@kyle-github
Copy link
Member

Is there something I can do in the core lib to help this? Would leveraging the callback API make this easier?

@timyhac
Copy link
Collaborator Author

timyhac commented Jan 20, 2021

I think the original purpose (September 2019) of this ticket (#5) has changed somewhat.

Originally this was going to test what has essentially become the NativeImport library. I'm not sure how to test this beyond manually testing to be honest. There was an idea to have a stub dll so that we could just check that the appropriate native method was called, but I'm not sure what the value of that is.

The purpose of this is now to test the stuff that the primary library adds on top of the native library (disposal of system resources, separation of async/sync, mapping of PLC types into .NET types) - so in fact I think it is better that the core library is not involved at all, otherwise the boundaries of the system-under-test blur.

@jkoplo
Copy link
Member

jkoplo commented Jan 20, 2021

Yeah, I see now why that would cause havoc.

From my perspective this looks solid, but we should probably document how the pieces fit together somewhere.

I don't think there's a ton of value in testing NativeImport package. We have to trust that the C library is good (via it's own testing). All we'd actually be testing is the .NET calls into C, and that's not real useful. The only other thing we could possibly test would be the extraction and override scenarios.

I think we merge this.

@timyhac
Copy link
Collaborator Author

timyhac commented Jan 20, 2021

Yep I agree with that sentiment @jkoplo

@timyhac timyhac merged commit a832ab6 into master Jan 20, 2021
@timyhac timyhac deleted the #5-automated-tests branch January 20, 2021 10:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants