You forget $query->the_post(), which makes the same as setup_postdata(). Also you are using $post->ID inside the loop but $post is not current post object in the loop. You have also syntax errors; for example you pass thumnail to wp_get_attachment_image() instead of a string "thumbnail", and pass name as orderby argument instead of the string "name", or ASC instead of "ASC":
<?php
//as you are inside a loop but I don't see $post variable in your code,
//I assume you want the current post in the loop as parent
$parent_id = get_the_ID();
$args = array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'posts_per_page' => 4,
'post_status' => 'inherit',
'post_parent' => $parent_id,
'orderby' => 'name',
'order' => 'ASC'
);
$attachments = new WP_Query($args);
while ($attachments->have_posts()) {
$attachments->the_post();
//I pass $parent_id to get_permalink() because you was trying
//to do that in your code but I'm not sure if this is what you want
?>
<a class="postpreview" href="https://wordpress.stackexchange.com/questions/143033/<?php echo get_permalink($parent_id); ?>"><?php echo wp_get_attachment_image(get_the_ID(), 'thumbnail') ?></a>
<?php
}
wp_reset_postdata();
?>
Anyway, new WP_query is not much better than get_posts(), each one has its benefits and the better depends on what you want to do.